library("tidyr")
library('ggplot2')
library('dplyr')
library("glue")
library('ggVennDiagram')

wkdir = "~/Desktop/GitHub/Obesity/NewExtractions/H9N2/timo_0.01"
setwd(wkdir)
savedir = "~/Desktop/GitHub/Obesity/NewExtractions/H9N2/timo_0.01/Output_Figures"

source("~/Desktop/GitHub/Obesity/NewExtractions/H9N2/FD_functions.R")
diet = c("Obese","Lean","Control")
dietColors = c("#FF9933","#66CCFF","#606060")
names(dietColors) = diet
DietcolScale_fill <- scale_fill_manual(name = "grp",values = dietColors)
DietcolScale <- scale_colour_manual(name = "grp",values = dietColors)

Specifying thresholds and plotting variables

cov_cut = 200
freq_cut = 0.01
pvalcut  = 0.05

ntlist = c("A","C","G","T")
SEGMENTS = c('H9N2_PB2','H9N2_PB1','H9N2_PA','H9N2_HA','H9N2_NP','H9N2_NA','H9N2_MP','H9N2_NS')

#Loading metadata This includes titer and Ct values when applicable. ND indicates qPCR was run with a negative result; 0 indicates plaque assay or HAI was run with a negative result. NA for any values indicate that data was missing. Sacrificed indicates there was no data at that time point because the ferret had already been sacrficied for pathology.

metafile = metafile = "~/Desktop/GitHub/Obesity/NewExtractions/H9N2/H9_Metadata.csv"

meta = read.csv(file=metafile,header=T,sep=",",na.strings = c(''))
meta = filter(meta, resequenced == "yes")

meta$Ct_Mgene = as.numeric(meta$Ct_Mgene)
Warning: NAs introduced by coercion
meta$titer = as.numeric(meta$titer)
Warning: NAs introduced by coercion
meta$log10_titer = as.numeric(meta$log10_titer)
Warning: NAs introduced by coercion
meta$inf_route = factor(meta$inf_route, levels = c("Index","Contact","Aerosol","Control"))

Loading in coverage file & segment size information

cov = read.csv("./avg_coverage/H9N2.coverage.csv", header = TRUE, sep = ",")

seg_sizes = "../SegmentSize.csv"
sizes = read.csv(file=seg_sizes,header=T,sep=",",na.strings = c(''))
GenomeSize = (sizes %>% filter(segment == 'H9N2_GENOME'))$SegmentSize

cov$segment = factor(cov$segment, levels = SEGMENTS)

Checking if data passes thresholds

cov_check = CoverageAcross(cov,cov_cut,40,sizes, wkdir)
Coverage cutoff is: 200x
Percentage covered cutoff is: 40%

Merging coverage check info with the rest of the metadata

meta = merge(meta, cov_check, by.x = c("sample"), by.y = c("name"), all.y = TRUE)

nrow(meta)
[1] 1536
count(meta,quality)

Loading in variant files

varfile = "./varfiles/H9N2.VariantsOnly.0.01.200.csv"

# read and rearrange the data
vars = read.csv(file=varfile,header=T,sep=",",na.strings = c(''))
vars$name = vars$sample

Rearranging variant dataframe

vdf = ArrangeVarWRep(vars)
# already have replicate data in the varfiles from running CompareReps.v2.py script
vdf = vdf[!duplicated(vdf), ] %>% droplevels()
nrow(vdf)
[1] 1781

Filtering variant df with frequency cutoffs

vdf = filter(vdf, minorfreq1 >= freq_cut & 
               minorfreq2 >= freq_cut & 
               minor %in% ntlist &
               major %in% ntlist) %>% 
            droplevels()
# based on MAF study, reps and 0.01% cutoff was best combo
#filter each replicate separately rather than using the average

vdf = vdf[!duplicated(vdf), ] %>% droplevels()
nrow(vdf)
[1] 1702
# does not eliminate any variants here

Filtering variant df by timo binocheck

#vdf$binocheck = factor(vdf$binocheck, levels = c("False","R1","R2","True"))
#vdf = filter(vdf, binocheck != "False") %>% unique()
#nrow(vdf)

# binocheck is highly dependent on the allele frequency threshold used and also relatively conservative
# as a result, ignore this in favor of found in both replicates across ferrets and cohorts - this is more indicative of a real variant than binocheck

Adding metadata

vdf = merge(vdf,meta, by = c("sample","segment"))
vdf = vdf[!duplicated(vdf), ] %>% droplevels()

vdf$segment = factor(vdf$segment, levels = SEGMENTS)

vdf = filter(vdf, inf_route == "Index" | inf_route == "Contact" | inf_route == "Control")
# ignoring aerosol for now

vdf = filter(vdf, !(ferretID == 2232 & inf_route == "Index"))
# since 2232 is both a contact and then an index to another contact, remove the second instance so as not to double count
# aka only consider 2232 as a contact
vdf = filter(vdf, quality == "good")
vdf = vdf[!duplicated(vdf), ] %>% droplevels()

good_names = c(levels(factor(vdf$sample)))
transmission_info = "/Users/marissaknoll/Desktop/GitHub/Obesity/NewExtractions/H9N2/TransmissionPairs.csv"
pairs = read.csv(transmission_info, header = T)
con_change = filter(vdf, stocknt != major) %>%
  filter(major %in% ntlist)
con_change = con_change[!duplicated(con_change), ]
con_change$ntvarpos = paste0(con_change$segment,"_",con_change$ntpos)
consensus = unique(con_change$ntvar)
length(consensus)
[1] 11
vdf$ntvarpos = paste0(vdf$segment,"_",vdf$ntpos)

minorvdf = filter(vdf, !(ntvarpos %in% consensus)) %>% unique()
nrow(vdf) - nrow(minorvdf)
[1] 212

SNV location plots

SNVLocation = ggplot(vdf, aes(x = ntpos, y = ferretID)) +
  geom_point(aes(color = diet, shape = cohort)) +
  facet_grid(inf_route~segment) +
  PlotTheme1 +
  DietcolScale
print(SNVLocation)
ggsave(SNVLocation, file = "SNVLocation.pdf", path = savedir)
Saving 7.29 x 4.51 in image

# ferret 1787 doesn't have any variants??
# Comparing to SNVs found in the stock
# changed to include consensus variants 9/14/23

F17_stock = filter(vdf, DPI == "Stock", cohort == "F17") 
F17_stock_ntvarpos = unique(F17_stock$ntvarpos)
W17_stock = filter(vdf, DPI == "Stock", cohort == "W17")
W17_stock_ntvarpos = unique(W17_stock$ntvarpos)
Sm18_stock = filter(vdf, DPI == "Stock", cohort == "Sm18")
Sm18_stock_ntvarpos = unique(Sm18_stock$ntvarpos)
Sp19_stock = filter(vdf, DPI == "Stock", cohort == "Sp19")
Sp19_stock_ntvarpos = unique(Sp19_stock$ntvarpos)
Sp20_stock = filter(vdf, DPI == "Stock", cohort == "Sp20")
Sp20_stock_ntvarpos = unique(Sp20_stock$ntvarpos)

F17_ferret = filter(vdf , cohort == "F17", inf_route != "Control")
F17_ferret_ntvarpos = unique(F17_ferret$ntvarpos)
W17_ferret = filter(vdf ,cohort == "W17", inf_route != "Control")
W17_ferret_ntvarpos = unique(W17_ferret$ntvarpos)
Sm18_ferret = filter(vdf ,cohort == "Sm18", inf_route != "Control")
Sm18_ferret_ntvarpos = unique(Sm18_ferret$ntvarpos)
Sp19_ferret = filter(vdf ,cohort == "Sp19", inf_route != "Control")
Sp19_ferret_ntvarpos = unique(Sp19_ferret$ntvarpos)
Sp20_ferret = filter(vdf ,cohort == "Sp20", inf_route != "Control")
Sp20_ferret_ntvarpos = unique(Sp20_ferret$ntvarpos)

all_stock_var = rbind(F17_stock, W17_stock, Sm18_stock, Sp19_stock, Sp20_stock) %>% select(sample, ntvarpos, aapos, major, majoraa, minor, minoraa, minorfreq, nonsyn)
write.csv(all_stock_var, "all_stock_var.csv", row.names = FALSE)
F17_shared = F17_ferret %>% filter(ntvarpos %in% F17_stock_ntvarpos) %>% filter((ntvarpos %in% F17_ferret_ntvarpos)) %>% unique()
F17_denovo = F17_ferret %>% filter((ntvarpos %in% F17_ferret_ntvarpos)) %>% filter(!(ntvarpos %in% F17_stock_ntvarpos)) %>% unique()

W17_shared = W17_ferret %>% filter(ntvarpos %in% W17_stock_ntvarpos) %>% filter((ntvarpos %in% W17_ferret_ntvarpos)) %>% unique()
W17_denovo = W17_ferret %>% filter((ntvarpos %in% W17_ferret_ntvarpos)) %>% filter(!(ntvarpos %in% W17_stock_ntvarpos)) %>% unique()

Sm18_shared = Sm18_ferret %>% filter(ntvarpos %in% Sm18_stock_ntvarpos) %>% filter((ntvarpos %in% Sm18_ferret_ntvarpos)) %>% unique()
Sm18_denovo = Sm18_ferret %>% filter((ntvarpos %in% Sm18_ferret_ntvarpos)) %>% filter(!(ntvarpos %in% Sm18_stock_ntvarpos)) %>% unique()

Sp19_shared = Sp19_ferret %>% filter(ntvarpos %in% Sp19_stock_ntvarpos) %>% filter((ntvarpos %in% Sp19_ferret_ntvarpos)) %>% unique()
Sp19_denovo = Sp19_ferret %>% filter((ntvarpos %in% Sp19_ferret_ntvarpos)) %>% filter(!(ntvarpos %in% Sp19_stock_ntvarpos)) %>% unique()

Sp20_shared = Sp20_ferret %>% filter(ntvarpos %in% Sp20_stock_ntvarpos) %>% filter((ntvarpos %in% Sp20_ferret_ntvarpos)) %>% unique()
Sp20_denovo = Sp20_ferret %>% filter((ntvarpos %in% Sp20_ferret_ntvarpos)) %>% filter(!(ntvarpos %in% Sp20_stock_ntvarpos)) %>% unique()

SNV Location compared to stock

StockSharedPlot = ggplot(stock_shared, aes(x = ntpos, y = ferretID)) +
  geom_point(aes(color = diet, shape = cohort), size = 2) +
  facet_grid(inf_route~segment, drop = FALSE) +
  PlotTheme1 +
  DietcolScale +
  ggtitle("SNVs found in stock")
print(StockSharedPlot)
ggsave(StockSharedPlot, file = "StockSharedPlot.pdf", height = 30, width = 15, path = savedir)


FerUniquePlot = ggplot(ferunique, aes(x = ntpos, y = ferretID)) +
  geom_point(aes(color = diet)) +
  facet_grid(inf_route~segment) +
  PlotTheme1 +
  DietcolScale +
  ggtitle("SNVs not found in stock")
print(FerUniquePlot)
ggsave(FerUniquePlot, file = "FerUniquePlot.pdf", path = savedir)
Saving 7.29 x 4.51 in image

Shared de novo SNVS

ferunique$ntvar = paste0(ferunique$segment,"_",ferunique$major,ferunique$ntpos,ferunique$minor)

shared_vars = ferunique %>% 
  group_by(ntvar,ferretID) %>% 
  tally() %>%
  group_by(ntvar) %>% # This is to prevent double counting variants within a same ferret but different dpi
  tally() %>% filter(n > 1) %>% unique()

# 100 variants that are shared between any ferrets
shared_denovominors = unique(shared_vars$ntvar)
df_allshared = filter(ferunique, ntvar %in% shared_denovominors)

Obese- and lean-specific SNVs

o_var = filter(df_allshared, diet == "Obese") 
o_var = unique(o_var$ntvar)

l_var = filter(df_allshared, diet == "Lean") 
l_var = unique(l_var$ntvar)

diet_var <- list(Obese = o_var, Lean = l_var)

# Venn diagram of obese and lean de novo shared SNVs
DietUniqueSNVS = ggVennDiagram(diet_var)
print(DietUniqueSNVS)
ggsave(DietUniqueSNVS, file = "DietUniqueSNVS.pdf", path = savedir)
Saving 7.29 x 4.51 in image

# 100 total - 67 shared between obese and lean, 20 obese specific, 13 lean specific 
lean = df_allshared %>%
  filter(ntvar %in% l_var) %>%
  filter(!(ntvar %in% o_var)) %>% 
  unique()
unique(lean$ntvar)
 [1] "H9N2_HA_G651A"   "H9N2_HA_C802T"   "H9N2_MP_G339A"   "H9N2_PB1_T1604C" "H9N2_PB1_G738A"  "H9N2_HA_C1118T"  "H9N2_PA_G1986A" 
 [8] "H9N2_HA_G808A"   "H9N2_NS_G294A"   "H9N2_NS_G374A"   "H9N2_NS_G660A"   "H9N2_NS_T375A"   "H9N2_HA_A1531T" 
lean$ferretID_var = paste0(lean$ferretID,"_",lean$ntvar)

repeats_lean = lean %>% 
  group_by(ntvar,ferretID) %>% 
  tally() %>%
  group_by(ntvar) %>% # This is to prevent double counting variants within a same ferret but different dpi
  tally() %>% unique()

lean = merge(lean, repeats_lean, by = c("ntvar")) %>% unique()

obese = df_allshared %>% 
  filter(ntvar %in% o_var) %>% 
  filter(!(ntvar %in% l_var)) %>%
  unique()
unique(obese$ntvar)
 [1] "H9N2_HA_A658G"   "H9N2_HA_C383A"   "H9N2_MP_G459A"   "H9N2_NA_G452A"   "H9N2_NA_G72A"    "H9N2_NS_A719G"   "H9N2_PB2_A1351T"
 [8] "H9N2_PB2_A480G"  "H9N2_PB2_A482G"  "H9N2_MP_T444C"   "H9N2_NP_T911C"   "H9N2_PB1_T905C"  "H9N2_PB1_T906C"  "H9N2_PB2_C1928G"
[15] "H9N2_HA_C375T"   "H9N2_PB1_G591A"  "H9N2_PA_C1873T"  "H9N2_NP_C249T"   "H9N2_HA_A747G"   "H9N2_PA_C1782A" 
obese$ferretID_var = paste0(obese$ferretID,"_",obese$ntvar)

repeats_obese = obese %>% 
  group_by(ntvar,ferretID) %>% 
  tally() %>%
  group_by(ntvar) %>% # This is to prevent double counting variants within a same ferret but different dpi
  tally() %>%
  unique()

obese = merge(obese, repeats_obese, by = c("ntvar")) %>% unique()

dietunique = rbind(lean,obese) %>% unique()
dietunique$ferret_num = dietunique$n
dietunique = select(dietunique, !(n))
#had to look up these positions manually
MP_G459A = filter(dietunique, ntvar == "H9N2_MP_G459A") %>% unique()
MP_G459A$nonsyn = "syn"
MP_G459A$aavar = "Q153Q"
MP_T444C = filter(dietunique, ntvar == "H9N2_MP_T444C") %>% unique()
MP_T444C$nonsyn = "syn"
MP_T444C$aavar = "C148C"
MP_G339A = filter(dietunique, ntvar == "H9N2_MP_G339A") %>% unique()
MP_G339A$nonsyn = "syn"
MP_G339A$aavar = "K113K"

MPs = c("H9N2_MP_G459A","H9N2_MP_T444C","H9N2_MP_G339A")
rest = filter(dietunique, !(ntvar %in% MPs)) %>% unique()
dietunique = rbind(rest, MP_G459A,MP_T444C,MP_G339A)

AF and emergence of obese-specific variantss

# What is the AF distribution of obese-specific variants
ggplot(filter(dietunique, diet == "Obese" & nonsyn == "nonsyn" & ferret_num == 2), aes(x = minorfreq)) +
  geom_histogram(binwidth = 0.01) +
  PlotTheme1


ggplot(filter(dietunique, diet == "Obese" & nonsyn == "nonsyn" & ferret_num == 2), aes(x = inf_route, y = minorfreq)) +
  geom_boxplot() +
  #facet_grid(~inf_route) +
  PlotTheme1


# Obese apadtation -> higher AF than non shared?
o_in = filter(dietunique, diet == "Obese" & nonsyn == "nonsyn" & ferret_num == 2 & inf_route == "Index")
o_co = filter(dietunique, diet == "Obese" & nonsyn == "nonsyn" & ferret_num == 2 & inf_route == "Contact")
t.test(o_in$minorfreq, o_co$minorfreq)

    Welch Two Sample t-test

data:  o_in$minorfreq and o_co$minorfreq
t = -1.1364, df = 15.17, p-value = 0.2734
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.07033827  0.02138534
sample estimates:
 mean of x  mean of y 
0.03827363 0.06275010 
# Diet adaptation (lean and obese) -> higher AF than non shared?
ind = filter(dietunique, nonsyn == "nonsyn" & ferret_num == 2 & inf_route == "Index")
#t.test(ind$minorfreq,non_share$minorfreq)
#
# Do they persist
lean2 = ferunique %>% 
  filter(ntvar %in% l_var) %>% 
  filter(!(ntvar %in% o_var)) %>% 
  unique()
lean2$ferretID_var = paste0(lean2$ferretID,"_",lean2$ntvar)

repeats_lean2 = lean2 %>% 
  mutate(count = 1) %>%
  group_by(ntvar,ferretID) %>% mutate(day_num = sum(count)) %>% ungroup()

lean_fers = select(repeats_lean2, ntvar, ferretID) %>% unique() %>% group_by(ntvar) %>% tally()
lean_fers$fer_num = lean_fers$n
lean_fers = select(lean_fers, !(n))
lean_wrep = merge(repeats_lean2, lean_fers, by = "ntvar") %>% unique()

####

obese2 = ferunique %>% 
  filter(ntvar %in% o_var) %>% 
  filter(!(ntvar %in% l_var)) %>%
  unique()
obese2$ferretID_var = paste0(obese2$ferretID,"_",obese2$ntvar)

repeats_obese2 = obese2 %>% 
  mutate(count = 1) %>%
  group_by(ntvar,ferretID) %>% mutate(day_num = sum(count)) %>% ungroup() 
ob_fers = select(repeats_obese2, ntvar, ferretID) %>% unique() %>% group_by(ntvar) %>% tally()
ob_fers$fer_num = ob_fers$n
ob_fers = select(ob_fers, !(n))
obese_wrep = merge(repeats_obese2, ob_fers, by = "ntvar") %>% unique()

dietunique_repeats = rbind(obese_wrep,lean_wrep) %>% unique()
meta_good = filter(meta, quality == "good") %>% select(sample, quality)
dietunique_repeats_zeros = merge(dietunique_repeats, meta_good, all = TRUE) %>% unique()
persistence = ggplot(filter(dietunique_repeats, nonsyn == "nonsyn" & fer_num == 2), aes(x = DPI, y = minorfreq)) +
  geom_point(aes(color = ntvar)) +
  geom_line(aes(group = ntvar)) +
  facet_grid(~ferretID) +
  PlotTheme1
print(persistence)
ggsave(persistence, filename = "persistence.pdf", path = savedir, width = 25, height = 5)

# Emergence
timing = filter(dietunique, diet == "Obese" & nonsyn == "nonsyn" & ferret_num == 2) %>%
  mutate(count = 1) %>% 
  group_by(inf_route, DPI) %>%
  mutate(perday = sum(count)) %>%
  group_by(inf_route) %>% 
  mutate(pergroup = sum(count)) %>%
  mutate(day_ratio = perday / pergroup) %>%
  select(DPI,inf_route, perday,pergroup, day_ratio) %>% unique()

ggplot(timing, aes(x = DPI, y = day_ratio)) +
  geom_col() +
  facet_grid(~inf_route) +
  PlotTheme1


timing_bydiet = filter(dietunique,nonsyn == "nonsyn" & ferret_num == 2) %>%
  mutate(count = 1) %>% 
  group_by(diet,inf_route, DPI) %>%
  mutate(perday = sum(count)) %>%
  group_by(diet,inf_route) %>% 
  mutate(pergroup = sum(count)) %>%
  mutate(day_ratio = perday / pergroup) %>%
  select(DPI,diet,inf_route, perday,pergroup, day_ratio) %>% unique()

ggplot(timing_bydiet, aes(x = DPI, y = day_ratio)) +
  geom_col() +
  facet_grid(diet~inf_route) +
  PlotTheme1

Determining if diet-unique shared variants are transmitted

dietunique_pairs = merge(dietunique, pairs, by = c("ferretID"))

shared = filter(dietunique_pairs, ferret_num > 1)
t = unique(shared$ntvar)

transmitted = data.frame()

for(i in t){
  print(i)
  df = filter(shared, ntvar == i) 
  df1 = df %>% 
  group_by(ntvar,ferretID,pair_numbers) %>% tally() %>% #this is to avoid double counting variants present at multiple DPI in same ferret
  group_by(pair_numbers) %>% tally()
  # here a 2 means that the two ferrets are in the same transmission pair and a 1 indicates different transmission pairs
  df2 = merge(df, df1, by = c("pair_numbers"))
  # add this information back into the dataframe
  df2$transmission = df2$n
  transmitted = rbind(transmitted, df2)
}
[1] "H9N2_NS_A719G"
[1] "H9N2_PB2_A480G"
[1] "H9N2_NA_G72A"
[1] "H9N2_NA_G452A"
[1] "H9N2_HA_C383A"
[1] "H9N2_MP_G459A"
[1] "H9N2_PB2_A1351T"
[1] "H9N2_HA_A658G"
[1] "H9N2_PB1_T905C"
[1] "H9N2_PB2_A482G"
[1] "H9N2_MP_T444C"
[1] "H9N2_NP_T911C"
[1] "H9N2_PB1_T906C"
[1] "H9N2_HA_C802T"
[1] "H9N2_HA_G808A"
[1] "H9N2_PB2_C1928G"
[1] "H9N2_PA_G1986A"
[1] "H9N2_NS_G294A"
[1] "H9N2_HA_G651A"
[1] "H9N2_MP_G339A"
[1] "H9N2_PB1_G738A"
[1] "H9N2_PB1_T1604C"
[1] "H9N2_HA_C1118T"
[1] "H9N2_HA_C375T"
[1] "H9N2_PB1_G591A"
[1] "H9N2_NS_G660A"
[1] "H9N2_NS_G374A"
[1] "H9N2_NS_T375A"
[1] "H9N2_PA_C1873T"
[1] "H9N2_NP_C249T"
[1] "H9N2_HA_A747G"
[1] "H9N2_PA_C1782A"
[1] "H9N2_HA_A1531T"
#formatting stuff
transmitted$transmission = as.character(transmitted$n)
transmitted = transmitted %>% select(!(n))

Removing possible transmissions since they would not be considered recurrent

recurrent = filter(transmitted, transmission == "1")
select(recurrent, ntvar, diet) %>% unique() %>% count(diet)
recurrent_dNdS = group_by(recurrent, diet, nonsyn) %>% tally() %>% 
  pivot_wider(names_from = nonsyn, values_from = n) %>%
  mutate(dNdS = nonsyn/syn)

DietUnique_Recurrent = ggplot(recurrent, 
                              aes(x = ntpos, 
                                  y = factor(segment, 
                                             levels = c('H9N2_NS','H9N2_MP','H9N2_NA','H9N2_NP','H9N2_HA','H9N2_PA','H9N2_PB1','H9N2_PB2')))) +
  geom_point(aes(color = nonsyn, size = 2)) + 
  geom_text(data = filter(recurrent, ferret_num == 2, nonsyn == "nonsyn"), aes(label = aavar, vjust = 2, hjust = 0.5)) +
  xlab("Nucleotide position") +
  ylab("Segment") +
  facet_grid(~diet) +
  PlotTheme1
print(DietUnique_Recurrent)
ggsave(DietUnique_Recurrent, file = "DietUnique_Recurrent.pdf", width = 10, height = 5, path = savedir)

Looking at transmitted minor vars

trans_var = filter(transmitted, transmission == "2")
select(trans_var, ntvar, diet) %>% unique() %>% count(diet)

transmitted_denovo_minors = ggplot(trans_var,aes(x = ntpos,y = factor(segment, 
                                             levels = c('H9N2_NS','H9N2_MP','H9N2_NA','H9N2_NP','H9N2_HA','H9N2_PA','H9N2_PB1','H9N2_PB2')))) +
  geom_point(aes(color = nonsyn, size = 2)) + 
  geom_text(data = filter(trans_var, ferret_num == 2), aes(label = aavar, vjust = 2, hjust = 0.5)) +
  xlab("Nucleotide position") +
  ylab("Segment") +
  facet_grid(pair_numbers+pair_diets~inf_route) +
  PlotTheme2
print(transmitted_denovo_minors)
ggsave(transmitted_denovo_minors, file = "DietUnique_Transmitted.pdf",  width = 7, height = 5, path = savedir)

SNVs shared between diet groups

shared = df_allshared %>% 
  filter(ntvar %in% o_var) %>% 
  filter(ntvar %in% l_var) %>% 
  unique()
shared$ferretID_var = paste0(shared$ferretID,"_",shared$ntvar)

repeats_shared = shared %>% 
  group_by(ntvar,ferretID) %>% 
  tally() %>%
  group_by(ntvar) %>%
  tally()
# this is to make sure I'm not repeatedly counting a variant found in one ferret but multiple days 

shared = merge(shared, repeats_shared, by = c("ntvar")) %>% unique()

SharedPlot = ggplot(shared, 
                    aes(x = ntpos,
                        y = factor(segment, levels = c('H9N2_NS','H9N2_MP','H9N2_NA','H9N2_NP','H9N2_HA','H9N2_PA','H9N2_PB1','H9N2_PB2')))) +
  geom_point(aes(size = n, color = nonsyn)) +
  geom_text(data = filter(shared, n > 4, nonsyn == "nonsyn"), aes(label = aavar, vjust = 2, hjust = 0.5)) +
  ggtitle("Number of samples containing each variant - Shared between diet groups") +
  ylab("Segment") +
  xlab("Nucleotide Position") +
  PlotTheme1
print(SharedPlot)
ggsave(SharedPlot, filename = "SegmentSNVPlot_DietShared.pdf", path = savedir, height = 10, width = 9)

Extracting common nonsynonymous variants shared between diet groups

nonsyns_shared = filter(shared, nonsyn == "nonsyn" & n > 1) %>% 
  ungroup() %>% 
  select(ntvar,aavar,minorfreq,n) %>%
  unique() %>%
  arrange(desc(n))

write.table(nonsyns_shared, "nonsyns_shared.csv", sep = ",", row.names = FALSE)

Are there differences in AF between diet-specific and non-diet-specific shared vars?

ggplot(shared, aes(x = minorfreq)) +
  geom_histogram()

ggplot(transmitted, aes(x = minorfreq)) +
  geom_histogram()


t.test(shared$minorfreq, transmitted$minorfreq)

    Welch Two Sample t-test

data:  shared$minorfreq and transmitted$minorfreq
t = 0.91334, df = 107.91, p-value = 0.3631
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.007424891  0.020114228
sample estimates:
 mean of x  mean of y 
0.04791309 0.04156843 

Are there differences in allele freq within the shared variants?

ggplot(shared, aes(x = minorfreq)) +
  geom_density(aes(group = factor(n, levels = c("2","3","4","5","6","7","8","9","10","22")), 
                     fill = factor(n, levels = c("2","3","4","5","6","7","8","9","10","22")),
                   alpha = 0.2))


select(nonsyns_shared, !minorfreq) %>% unique() %>% ggplot(., aes(x = n)) + geom_histogram(binwidth = 1)

# determining cutoffs for high and low shared

low_shared = filter(shared, n < 5) %>% unique() %>% mutate(cat = "low")
high_shared = filter(shared, n > 5) %>% unique() %>% mutate(cat = "high")
all_shared = rbind(low_shared, high_shared)

ggplot(low_shared, aes(x = minorfreq)) +
  geom_histogram(binwidth = 0.01)


ggplot(high_shared, aes(x = minorfreq)) +
  geom_histogram(binwidth = 0.01)


ggplot(all_shared, aes(x = minorfreq)) +
  geom_density(aes(group = cat, fill = cat), alpha = 0.4)


t.test(low_shared$minorfreq, high_shared$minorfreq)

    Welch Two Sample t-test

data:  low_shared$minorfreq and high_shared$minorfreq
t = 1.9828, df = 265.48, p-value = 0.04842
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 8.386903e-05 2.391033e-02
sample estimates:
 mean of x  mean of y 
0.05023738 0.03824028 

Are there differences in AF between shared and non shared variants?

oneferret = select(ferunique,ntvar, minorfreq, sample) %>% unique() %>% count(ntvar) %>% filter(n == 1) 
oneferret = unique(oneferret$ntvar)
singles = filter(ferunique, ntvar %in% oneferret) %>% unique()

non_share = select(singles, ntvar, aavar, minorfreq) %>% mutate(n = 1)
non_share$cat = "not shared"

ggplot(non_share, aes(x = minorfreq)) +
  geom_histogram(binwidth = 0.01)

all_shared$cat = "shared"

all_shared_sub = select(all_shared, ntvar, aavar, minorfreq, n, cat)

try_all = rbind(all_shared_sub, non_share) %>% unique()

ggplot(try_all, aes(x = minorfreq)) +
  geom_density(aes(group = cat, fill = cat), alpha = 0.4)


t.test(non_share$minorfreq, low_shared$minorfreq)

    Welch Two Sample t-test

data:  non_share$minorfreq and low_shared$minorfreq
t = -3.3303, df = 220.49, p-value = 0.001017
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.029091318 -0.007460915
sample estimates:
 mean of x  mean of y 
0.03196126 0.05023738 
t.test(non_share$minorfreq, high_shared$minorfreq)

    Welch Two Sample t-test

data:  non_share$minorfreq and high_shared$minorfreq
t = -1.5486, df = 255.65, p-value = 0.1227
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.014263679  0.001705645
sample estimates:
 mean of x  mean of y 
0.03196126 0.03824028 

Combining all shared(btw obese and lean) compared to not shared

share_v_noshare_AF = ggplot(try_all, aes(y = minorfreq, x = cat, color = cat)) +
  geom_boxplot(outlier.shape = NA) + 
  #geom_jitter(alpha = 0.3) +
  ylim(0,0.1) +
  PlotTheme1
print(share_v_noshare_AF)
ggsave(share_v_noshare_AF, filename = "share_v_noshare_AF.pdf", path = savedir, height = 5, width = 9)


ggplot(try_all, aes(y = minorfreq, x = cat, color = cat)) +
  geom_violin() +
  PlotTheme1


t.test(non_share$minorfreq, all_shared$minorfreq)

    Welch Two Sample t-test

data:  non_share$minorfreq and all_shared$minorfreq
t = -3.3153, df = 553.28, p-value = 0.0009755
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.020342423 -0.005205575
sample estimates:
 mean of x  mean of y 
0.03196126 0.04473526 

Is there a difference in freq or abundance between obese v lean ferrets of the 67 non-diet-specific shared vars?

# Frequency
ggplot(shared, aes(x = diet, y = minorfreq)) +
  geom_boxplot(aes(color = diet)) +
  DietcolScale +
  PlotTheme2

shared_ln = filter(shared, diet == "Lean")
shared_ob = filter(shared, diet == "Obese")
t.test(shared_ln$minorfreq,shared_ob$minorfreq)

    Welch Two Sample t-test

data:  shared_ln$minorfreq and shared_ob$minorfreq
t = -1.5297, df = 328.34, p-value = 0.1271
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.021343913  0.002670577
sample estimates:
 mean of x  mean of y 
0.04323066 0.05256732 
# Abundance
shared_vars = group_by(shared, ntvar, diet) %>% tally() 

ggplot(shared_vars, aes(x = ntvar, y = n, fill = diet)) +
geom_col(position = "dodge") + 
#facet_grid(~inf_route) +
PlotTheme1 +
DietcolScale_fill


diff_shared_vars = group_by(shared, ntvar, diet) %>% 
  tally() %>% 
  pivot_wider(names_from = diet, values_from = n) %>% 
  mutate(diff = abs(Obese - Lean)) %>% 
  filter(diff > 2) %>%
  pivot_longer(cols = c("Lean", "Obese"), names_to = c("diet"))
  
ggplot(diff_shared_vars, aes(x = ntvar, y = value, fill = diet)) +
geom_col(position = "dodge") +
#facet_grid(~inf_route) +
PlotTheme1 +
DietcolScale_fill

#Is there a difference in AF of the variants found in obese and lean ferrets?

ggplot(shared, aes(x = minorfreq, fill = diet)) +
  geom_histogram(binwidth = 0.01) +
  PlotTheme1 +
  facet_grid(inf_route~diet) +
  DietcolScale_fill


o = filter(shared, inf_route == "Index" & diet == "Obese")
l = filter(shared, inf_route == "Index" & diet == "Lean")
t.test(o$minorfreq, l$minorfreq)

    Welch Two Sample t-test

data:  o$minorfreq and l$minorfreq
t = 1.1423, df = 156.25, p-value = 0.2551
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.003206157  0.011999126
sample estimates:
 mean of x  mean of y 
0.03223299 0.02783651 
#not significantly different
obese_index = filter(ferunique, diet == "Obese" & inf_route == "Index") %>% ungroup()
lean_index = filter(ferunique, diet == "Lean" & inf_route == "Index") %>% ungroup()
t.test(obese_index$minorfreq, lean_index$minorfreq)

    Welch Two Sample t-test

data:  obese_index$minorfreq and lean_index$minorfreq
t = 1.3069, df = 401.02, p-value = 0.192
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.001593520  0.007914183
sample estimates:
 mean of x  mean of y 
0.03037901 0.02721868 
# means are not different

obese_contact = filter(ferunique, diet == "Obese" & inf_route == "Contact") %>% ungroup()
lean_contact = filter(ferunique, diet == "Lean" & inf_route == "Contact") %>% ungroup()
t.test(obese_contact$minorfreq, lean_contact$minorfreq)

    Welch Two Sample t-test

data:  obese_contact$minorfreq and lean_contact$minorfreq
t = 0.91384, df = 328.9, p-value = 0.3615
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.008520561  0.023304378
sample estimates:
 mean of x  mean of y 
0.06523254 0.05784063 
# means are not different

# QQ_Plot: compares the quantiles of two distributions, x =y suggests they are drawn from the same distribution
qqnorm(obese_index$minorfreq, main = "Obese Index - Test of Normal Distribution")

qqnorm(lean_index$minorfreq, main = "Lean Index - Test of Normal Distribution")

# neither distribution is normal
qqplot(obese_index$minorfreq,lean_index$minorfreq, xlab = "Obese Index", ylab = "Lean Index")


qqnorm(obese_contact$minorfreq, main = "Obese Contact - Test of Normal Distribution")

qqnorm(lean_contact$minorfreq, main = "Lean Contact - Test of Normal Distribution")

# neither distribution is normal
qqplot(obese_contact$minorfreq,lean_contact$minorfreq, xlab = "Obese Contact", ylab = "Lean Contact")


# Mann-Whitney-Wilcox test (Mann-Whitney U test): samples are not normally distributed and independent of each other
wilcox.test(obese_index$minorfreq,lean_index$minorfreq)

    Wilcoxon rank sum test with continuity correction

data:  obese_index$minorfreq and lean_index$minorfreq
W = 44444, p-value = 0.07889
alternative hypothesis: true location shift is not equal to 0
wilcox.test(obese_contact$minorfreq,lean_contact$minorfreq)

    Wilcoxon rank sum test with continuity correction

data:  obese_contact$minorfreq and lean_contact$minorfreq
W = 17434, p-value = 0.04737
alternative hypothesis: true location shift is not equal to 0
# distributions are not different

# Kolmogorov-Smirnov test: samples are not normally distributed and independent of each other
# "sensitive to differences in location and shape of the empirical CDFs of the two samples"
ks.test(obese_index$minorfreq,lean_index$minorfreq)

    Asymptotic two-sample Kolmogorov-Smirnov test

data:  obese_index$minorfreq and lean_index$minorfreq
D = 0.091481, p-value = 0.1993
alternative hypothesis: two-sided
ks.test(obese_contact$minorfreq,lean_contact$minorfreq)

    Asymptotic two-sample Kolmogorov-Smirnov test

data:  obese_contact$minorfreq and lean_contact$minorfreq
D = 0.16995, p-value = 0.01315
alternative hypothesis: two-sided
# distributions are not different
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoInRpZHlyIikKbGlicmFyeSgnZ2dwbG90MicpCmxpYnJhcnkoJ2RwbHlyJykKbGlicmFyeSgiZ2x1ZSIpCmxpYnJhcnkoJ2dnVmVubkRpYWdyYW0nKQoKd2tkaXIgPSAifi9EZXNrdG9wL0dpdEh1Yi9PYmVzaXR5L05ld0V4dHJhY3Rpb25zL0g5TjIvdGltb18wLjAxIgpzZXR3ZCh3a2RpcikKc2F2ZWRpciA9ICJ+L0Rlc2t0b3AvR2l0SHViL09iZXNpdHkvTmV3RXh0cmFjdGlvbnMvSDlOMi90aW1vXzAuMDEvT3V0cHV0X0ZpZ3VyZXMiCgpzb3VyY2UoIn4vRGVza3RvcC9HaXRIdWIvT2Jlc2l0eS9OZXdFeHRyYWN0aW9ucy9IOU4yL0ZEX2Z1bmN0aW9ucy5SIikKYGBgCgpgYGB7cn0KZGlldCA9IGMoIk9iZXNlIiwiTGVhbiIsIkNvbnRyb2wiKQpkaWV0Q29sb3JzID0gYygiI0ZGOTkzMyIsIiM2NkNDRkYiLCIjNjA2MDYwIikKbmFtZXMoZGlldENvbG9ycykgPSBkaWV0CkRpZXRjb2xTY2FsZV9maWxsIDwtIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiZ3JwIix2YWx1ZXMgPSBkaWV0Q29sb3JzKQpEaWV0Y29sU2NhbGUgPC0gc2NhbGVfY29sb3VyX21hbnVhbChuYW1lID0gImdycCIsdmFsdWVzID0gZGlldENvbG9ycykKYGBgCgojIFNwZWNpZnlpbmcgdGhyZXNob2xkcyBhbmQgcGxvdHRpbmcgdmFyaWFibGVzCmBgYHtyfQpjb3ZfY3V0ID0gMjAwCmZyZXFfY3V0ID0gMC4wMQpwdmFsY3V0ICA9IDAuMDUKCm50bGlzdCA9IGMoIkEiLCJDIiwiRyIsIlQiKQpTRUdNRU5UUyA9IGMoJ0g5TjJfUEIyJywnSDlOMl9QQjEnLCdIOU4yX1BBJywnSDlOMl9IQScsJ0g5TjJfTlAnLCdIOU4yX05BJywnSDlOMl9NUCcsJ0g5TjJfTlMnKQpgYGAKCiNMb2FkaW5nIG1ldGFkYXRhClRoaXMgaW5jbHVkZXMgdGl0ZXIgYW5kIEN0IHZhbHVlcyB3aGVuIGFwcGxpY2FibGUuIE5EIGluZGljYXRlcyBxUENSIHdhcyBydW4gd2l0aCBhIG5lZ2F0aXZlIHJlc3VsdDsgMCBpbmRpY2F0ZXMgcGxhcXVlIGFzc2F5IG9yIEhBSSB3YXMgcnVuIHdpdGggYSBuZWdhdGl2ZSByZXN1bHQuIE5BIGZvciBhbnkgdmFsdWVzIGluZGljYXRlIHRoYXQgZGF0YSB3YXMgbWlzc2luZy4gU2FjcmlmaWNlZCBpbmRpY2F0ZXMgdGhlcmUgd2FzIG5vIGRhdGEgYXQgdGhhdCB0aW1lIHBvaW50IGJlY2F1c2UgdGhlIGZlcnJldCBoYWQgYWxyZWFkeSBiZWVuIHNhY3JmaWNpZWQgZm9yIHBhdGhvbG9neS4gCmBgYHtyfQptZXRhZmlsZSA9IG1ldGFmaWxlID0gIn4vRGVza3RvcC9HaXRIdWIvT2Jlc2l0eS9OZXdFeHRyYWN0aW9ucy9IOU4yL0g5X01ldGFkYXRhLmNzdiIKCm1ldGEgPSByZWFkLmNzdihmaWxlPW1ldGFmaWxlLGhlYWRlcj1ULHNlcD0iLCIsbmEuc3RyaW5ncyA9IGMoJycpKQptZXRhID0gZmlsdGVyKG1ldGEsIHJlc2VxdWVuY2VkID09ICJ5ZXMiKQoKbWV0YSRDdF9NZ2VuZSA9IGFzLm51bWVyaWMobWV0YSRDdF9NZ2VuZSkKbWV0YSR0aXRlciA9IGFzLm51bWVyaWMobWV0YSR0aXRlcikKbWV0YSRsb2cxMF90aXRlciA9IGFzLm51bWVyaWMobWV0YSRsb2cxMF90aXRlcikKCm1ldGEkaW5mX3JvdXRlID0gZmFjdG9yKG1ldGEkaW5mX3JvdXRlLCBsZXZlbHMgPSBjKCJJbmRleCIsIkNvbnRhY3QiLCJBZXJvc29sIiwiQ29udHJvbCIpKQpgYGAKCiMgTG9hZGluZyBpbiBjb3ZlcmFnZSBmaWxlICYgc2VnbWVudCBzaXplIGluZm9ybWF0aW9uCmBgYHtyfQpjb3YgPSByZWFkLmNzdigiLi9hdmdfY292ZXJhZ2UvSDlOMi5jb3ZlcmFnZS5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIpCgpzZWdfc2l6ZXMgPSAiLi4vU2VnbWVudFNpemUuY3N2IgpzaXplcyA9IHJlYWQuY3N2KGZpbGU9c2VnX3NpemVzLGhlYWRlcj1ULHNlcD0iLCIsbmEuc3RyaW5ncyA9IGMoJycpKQpHZW5vbWVTaXplID0gKHNpemVzICU+JSBmaWx0ZXIoc2VnbWVudCA9PSAnSDlOMl9HRU5PTUUnKSkkU2VnbWVudFNpemUKCmNvdiRzZWdtZW50ID0gZmFjdG9yKGNvdiRzZWdtZW50LCBsZXZlbHMgPSBTRUdNRU5UUykKYGBgCgojIENoZWNraW5nIGlmIGRhdGEgcGFzc2VzIHRocmVzaG9sZHMKYGBge3J9CmNvdl9jaGVjayA9IENvdmVyYWdlQWNyb3NzKGNvdixjb3ZfY3V0LDQwLHNpemVzLCB3a2RpcikKYGBgCgojIE1lcmdpbmcgY292ZXJhZ2UgY2hlY2sgaW5mbyB3aXRoIHRoZSByZXN0IG9mIHRoZSBtZXRhZGF0YQpgYGB7cn0KbWV0YSA9IG1lcmdlKG1ldGEsIGNvdl9jaGVjaywgYnkueCA9IGMoInNhbXBsZSIpLCBieS55ID0gYygibmFtZSIpLCBhbGwueSA9IFRSVUUpCgpucm93KG1ldGEpCmNvdW50KG1ldGEscXVhbGl0eSkKYGBgCgojIExvYWRpbmcgaW4gdmFyaWFudCBmaWxlcwpgYGB7cn0KdmFyZmlsZSA9ICIuL3ZhcmZpbGVzL0g5TjIuVmFyaWFudHNPbmx5LjAuMDEuMjAwLmNzdiIKCiMgcmVhZCBhbmQgcmVhcnJhbmdlIHRoZSBkYXRhCnZhcnMgPSByZWFkLmNzdihmaWxlPXZhcmZpbGUsaGVhZGVyPVQsc2VwPSIsIixuYS5zdHJpbmdzID0gYygnJykpCnZhcnMkbmFtZSA9IHZhcnMkc2FtcGxlCmBgYAoKIyBSZWFycmFuZ2luZyB2YXJpYW50IGRhdGFmcmFtZQpgYGB7cn0KdmRmID0gQXJyYW5nZVZhcldSZXAodmFycykKIyBhbHJlYWR5IGhhdmUgcmVwbGljYXRlIGRhdGEgaW4gdGhlIHZhcmZpbGVzIGZyb20gcnVubmluZyBDb21wYXJlUmVwcy52Mi5weSBzY3JpcHQKdmRmID0gdmRmWyFkdXBsaWNhdGVkKHZkZiksIF0gJT4lIGRyb3BsZXZlbHMoKQpucm93KHZkZikKYGBgCgojIEZpbHRlcmluZyB2YXJpYW50IGRmIHdpdGggZnJlcXVlbmN5IGN1dG9mZnMKYGBge3J9CnZkZiA9IGZpbHRlcih2ZGYsIG1pbm9yZnJlcTEgPj0gZnJlcV9jdXQgJiAKICAgICAgICAgICAgICAgbWlub3JmcmVxMiA+PSBmcmVxX2N1dCAmIAogICAgICAgICAgICAgICBtaW5vciAlaW4lIG50bGlzdCAmCiAgICAgICAgICAgICAgIG1ham9yICVpbiUgbnRsaXN0KSAlPiUgCiAgICAgICAgICAgIGRyb3BsZXZlbHMoKQojIGJhc2VkIG9uIE1BRiBzdHVkeSwgcmVwcyBhbmQgMC4wMSUgY3V0b2ZmIHdhcyBiZXN0IGNvbWJvCiNmaWx0ZXIgZWFjaCByZXBsaWNhdGUgc2VwYXJhdGVseSByYXRoZXIgdGhhbiB1c2luZyB0aGUgYXZlcmFnZQoKdmRmID0gdmRmWyFkdXBsaWNhdGVkKHZkZiksIF0gJT4lIGRyb3BsZXZlbHMoKQpucm93KHZkZikKIyBkb2VzIG5vdCBlbGltaW5hdGUgYW55IHZhcmlhbnRzIGhlcmUKYGBgCgojIEZpbHRlcmluZyB2YXJpYW50IGRmIGJ5IHRpbW8gYmlub2NoZWNrCmBgYHtyfQojdmRmJGJpbm9jaGVjayA9IGZhY3Rvcih2ZGYkYmlub2NoZWNrLCBsZXZlbHMgPSBjKCJGYWxzZSIsIlIxIiwiUjIiLCJUcnVlIikpCiN2ZGYgPSBmaWx0ZXIodmRmLCBiaW5vY2hlY2sgIT0gIkZhbHNlIikgJT4lIHVuaXF1ZSgpCiNucm93KHZkZikKCiMgYmlub2NoZWNrIGlzIGhpZ2hseSBkZXBlbmRlbnQgb24gdGhlIGFsbGVsZSBmcmVxdWVuY3kgdGhyZXNob2xkIHVzZWQgYW5kIGFsc28gcmVsYXRpdmVseSBjb25zZXJ2YXRpdmUKIyBhcyBhIHJlc3VsdCwgaWdub3JlIHRoaXMgaW4gZmF2b3Igb2YgZm91bmQgaW4gYm90aCByZXBsaWNhdGVzIGFjcm9zcyBmZXJyZXRzIGFuZCBjb2hvcnRzIC0gdGhpcyBpcyBtb3JlIGluZGljYXRpdmUgb2YgYSByZWFsIHZhcmlhbnQgdGhhbiBiaW5vY2hlY2sKYGBgCgojIEFkZGluZyBtZXRhZGF0YQpgYGB7cn0KdmRmID0gbWVyZ2UodmRmLG1ldGEsIGJ5ID0gYygic2FtcGxlIiwic2VnbWVudCIpKQp2ZGYgPSB2ZGZbIWR1cGxpY2F0ZWQodmRmKSwgXSAlPiUgZHJvcGxldmVscygpCgp2ZGYkc2VnbWVudCA9IGZhY3Rvcih2ZGYkc2VnbWVudCwgbGV2ZWxzID0gU0VHTUVOVFMpCgp2ZGYgPSBmaWx0ZXIodmRmLCBpbmZfcm91dGUgPT0gIkluZGV4IiB8IGluZl9yb3V0ZSA9PSAiQ29udGFjdCIgfCBpbmZfcm91dGUgPT0gIkNvbnRyb2wiKQojIGlnbm9yaW5nIGFlcm9zb2wgZm9yIG5vdwoKdmRmID0gZmlsdGVyKHZkZiwgIShmZXJyZXRJRCA9PSAyMjMyICYgaW5mX3JvdXRlID09ICJJbmRleCIpKQojIHNpbmNlIDIyMzIgaXMgYm90aCBhIGNvbnRhY3QgYW5kIHRoZW4gYW4gaW5kZXggdG8gYW5vdGhlciBjb250YWN0LCByZW1vdmUgdGhlIHNlY29uZCBpbnN0YW5jZSBzbyBhcyBub3QgdG8gZG91YmxlIGNvdW50CiMgYWthIG9ubHkgY29uc2lkZXIgMjIzMiBhcyBhIGNvbnRhY3QKYGBgCgpgYGB7cn0KdmRmID0gZmlsdGVyKHZkZiwgcXVhbGl0eSA9PSAiZ29vZCIpCnZkZiA9IHZkZlshZHVwbGljYXRlZCh2ZGYpLCBdICU+JSBkcm9wbGV2ZWxzKCkKCmdvb2RfbmFtZXMgPSBjKGxldmVscyhmYWN0b3IodmRmJHNhbXBsZSkpKQpgYGAKCmBgYHtyfQp0cmFuc21pc3Npb25faW5mbyA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvR2l0SHViL09iZXNpdHkvTmV3RXh0cmFjdGlvbnMvSDlOMi9UcmFuc21pc3Npb25QYWlycy5jc3YiCnBhaXJzID0gcmVhZC5jc3YodHJhbnNtaXNzaW9uX2luZm8sIGhlYWRlciA9IFQpCmBgYAoKYGBge3J9CmNvbl9jaGFuZ2UgPSBmaWx0ZXIodmRmLCBzdG9ja250ICE9IG1ham9yKSAlPiUKICBmaWx0ZXIobWFqb3IgJWluJSBudGxpc3QpCmNvbl9jaGFuZ2UgPSBjb25fY2hhbmdlWyFkdXBsaWNhdGVkKGNvbl9jaGFuZ2UpLCBdCmNvbl9jaGFuZ2UkbnR2YXJwb3MgPSBwYXN0ZTAoY29uX2NoYW5nZSRzZWdtZW50LCJfIixjb25fY2hhbmdlJG50cG9zKQpjb25zZW5zdXMgPSB1bmlxdWUoY29uX2NoYW5nZSRudHZhcikKbGVuZ3RoKGNvbnNlbnN1cykKYGBgCgpgYGB7cn0KdmRmJG50dmFycG9zID0gcGFzdGUwKHZkZiRzZWdtZW50LCJfIix2ZGYkbnRwb3MpCgptaW5vcnZkZiA9IGZpbHRlcih2ZGYsICEobnR2YXJwb3MgJWluJSBjb25zZW5zdXMpKSAlPiUgdW5pcXVlKCkKbnJvdyh2ZGYpIC0gbnJvdyhtaW5vcnZkZikKYGBgCgpTTlYgbG9jYXRpb24gcGxvdHMKYGBge3J9ClNOVkxvY2F0aW9uID0gZ2dwbG90KHZkZiwgYWVzKHggPSBudHBvcywgeSA9IGZlcnJldElEKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGlldCwgc2hhcGUgPSBjb2hvcnQpKSArCiAgZmFjZXRfZ3JpZChpbmZfcm91dGV+c2VnbWVudCkgKwogIFBsb3RUaGVtZTEgKwogIERpZXRjb2xTY2FsZQpwcmludChTTlZMb2NhdGlvbikKZ2dzYXZlKFNOVkxvY2F0aW9uLCBmaWxlID0gIlNOVkxvY2F0aW9uLnBkZiIsIHBhdGggPSBzYXZlZGlyKQojIGZlcnJldCAxNzg3IGRvZXNuJ3QgaGF2ZSBhbnkgdmFyaWFudHM/PwpgYGAKCmBgYHtyfQojIENvbXBhcmluZyB0byBTTlZzIGZvdW5kIGluIHRoZSBzdG9jawojIGNoYW5nZWQgdG8gaW5jbHVkZSBjb25zZW5zdXMgdmFyaWFudHMgOS8xNC8yMwoKRjE3X3N0b2NrID0gZmlsdGVyKHZkZiwgRFBJID09ICJTdG9jayIsIGNvaG9ydCA9PSAiRjE3IikgCkYxN19zdG9ja19udHZhcnBvcyA9IHVuaXF1ZShGMTdfc3RvY2skbnR2YXJwb3MpClcxN19zdG9jayA9IGZpbHRlcih2ZGYsIERQSSA9PSAiU3RvY2siLCBjb2hvcnQgPT0gIlcxNyIpClcxN19zdG9ja19udHZhcnBvcyA9IHVuaXF1ZShXMTdfc3RvY2skbnR2YXJwb3MpClNtMThfc3RvY2sgPSBmaWx0ZXIodmRmLCBEUEkgPT0gIlN0b2NrIiwgY29ob3J0ID09ICJTbTE4IikKU20xOF9zdG9ja19udHZhcnBvcyA9IHVuaXF1ZShTbTE4X3N0b2NrJG50dmFycG9zKQpTcDE5X3N0b2NrID0gZmlsdGVyKHZkZiwgRFBJID09ICJTdG9jayIsIGNvaG9ydCA9PSAiU3AxOSIpClNwMTlfc3RvY2tfbnR2YXJwb3MgPSB1bmlxdWUoU3AxOV9zdG9jayRudHZhcnBvcykKU3AyMF9zdG9jayA9IGZpbHRlcih2ZGYsIERQSSA9PSAiU3RvY2siLCBjb2hvcnQgPT0gIlNwMjAiKQpTcDIwX3N0b2NrX250dmFycG9zID0gdW5pcXVlKFNwMjBfc3RvY2skbnR2YXJwb3MpCgpGMTdfZmVycmV0ID0gZmlsdGVyKHZkZiAsIGNvaG9ydCA9PSAiRjE3IiwgaW5mX3JvdXRlICE9ICJDb250cm9sIikKRjE3X2ZlcnJldF9udHZhcnBvcyA9IHVuaXF1ZShGMTdfZmVycmV0JG50dmFycG9zKQpXMTdfZmVycmV0ID0gZmlsdGVyKHZkZiAsY29ob3J0ID09ICJXMTciLCBpbmZfcm91dGUgIT0gIkNvbnRyb2wiKQpXMTdfZmVycmV0X250dmFycG9zID0gdW5pcXVlKFcxN19mZXJyZXQkbnR2YXJwb3MpClNtMThfZmVycmV0ID0gZmlsdGVyKHZkZiAsY29ob3J0ID09ICJTbTE4IiwgaW5mX3JvdXRlICE9ICJDb250cm9sIikKU20xOF9mZXJyZXRfbnR2YXJwb3MgPSB1bmlxdWUoU20xOF9mZXJyZXQkbnR2YXJwb3MpClNwMTlfZmVycmV0ID0gZmlsdGVyKHZkZiAsY29ob3J0ID09ICJTcDE5IiwgaW5mX3JvdXRlICE9ICJDb250cm9sIikKU3AxOV9mZXJyZXRfbnR2YXJwb3MgPSB1bmlxdWUoU3AxOV9mZXJyZXQkbnR2YXJwb3MpClNwMjBfZmVycmV0ID0gZmlsdGVyKHZkZiAsY29ob3J0ID09ICJTcDIwIiwgaW5mX3JvdXRlICE9ICJDb250cm9sIikKU3AyMF9mZXJyZXRfbnR2YXJwb3MgPSB1bmlxdWUoU3AyMF9mZXJyZXQkbnR2YXJwb3MpCgphbGxfc3RvY2tfdmFyID0gcmJpbmQoRjE3X3N0b2NrLCBXMTdfc3RvY2ssIFNtMThfc3RvY2ssIFNwMTlfc3RvY2ssIFNwMjBfc3RvY2spICU+JSBzZWxlY3Qoc2FtcGxlLCBudHZhcnBvcywgYWFwb3MsIG1ham9yLCBtYWpvcmFhLCBtaW5vciwgbWlub3JhYSwgbWlub3JmcmVxLCBub25zeW4pCndyaXRlLmNzdihhbGxfc3RvY2tfdmFyLCAiYWxsX3N0b2NrX3Zhci5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgpgYGB7cn0KRjE3X3NoYXJlZCA9IEYxN19mZXJyZXQgJT4lIGZpbHRlcihudHZhcnBvcyAlaW4lIEYxN19zdG9ja19udHZhcnBvcykgJT4lIGZpbHRlcigobnR2YXJwb3MgJWluJSBGMTdfZmVycmV0X250dmFycG9zKSkgJT4lIHVuaXF1ZSgpCkYxN19kZW5vdm8gPSBGMTdfZmVycmV0ICU+JSBmaWx0ZXIoKG50dmFycG9zICVpbiUgRjE3X2ZlcnJldF9udHZhcnBvcykpICU+JSBmaWx0ZXIoIShudHZhcnBvcyAlaW4lIEYxN19zdG9ja19udHZhcnBvcykpICU+JSB1bmlxdWUoKQoKVzE3X3NoYXJlZCA9IFcxN19mZXJyZXQgJT4lIGZpbHRlcihudHZhcnBvcyAlaW4lIFcxN19zdG9ja19udHZhcnBvcykgJT4lIGZpbHRlcigobnR2YXJwb3MgJWluJSBXMTdfZmVycmV0X250dmFycG9zKSkgJT4lIHVuaXF1ZSgpClcxN19kZW5vdm8gPSBXMTdfZmVycmV0ICU+JSBmaWx0ZXIoKG50dmFycG9zICVpbiUgVzE3X2ZlcnJldF9udHZhcnBvcykpICU+JSBmaWx0ZXIoIShudHZhcnBvcyAlaW4lIFcxN19zdG9ja19udHZhcnBvcykpICU+JSB1bmlxdWUoKQoKU20xOF9zaGFyZWQgPSBTbTE4X2ZlcnJldCAlPiUgZmlsdGVyKG50dmFycG9zICVpbiUgU20xOF9zdG9ja19udHZhcnBvcykgJT4lIGZpbHRlcigobnR2YXJwb3MgJWluJSBTbTE4X2ZlcnJldF9udHZhcnBvcykpICU+JSB1bmlxdWUoKQpTbTE4X2Rlbm92byA9IFNtMThfZmVycmV0ICU+JSBmaWx0ZXIoKG50dmFycG9zICVpbiUgU20xOF9mZXJyZXRfbnR2YXJwb3MpKSAlPiUgZmlsdGVyKCEobnR2YXJwb3MgJWluJSBTbTE4X3N0b2NrX250dmFycG9zKSkgJT4lIHVuaXF1ZSgpCgpTcDE5X3NoYXJlZCA9IFNwMTlfZmVycmV0ICU+JSBmaWx0ZXIobnR2YXJwb3MgJWluJSBTcDE5X3N0b2NrX250dmFycG9zKSAlPiUgZmlsdGVyKChudHZhcnBvcyAlaW4lIFNwMTlfZmVycmV0X250dmFycG9zKSkgJT4lIHVuaXF1ZSgpClNwMTlfZGVub3ZvID0gU3AxOV9mZXJyZXQgJT4lIGZpbHRlcigobnR2YXJwb3MgJWluJSBTcDE5X2ZlcnJldF9udHZhcnBvcykpICU+JSBmaWx0ZXIoIShudHZhcnBvcyAlaW4lIFNwMTlfc3RvY2tfbnR2YXJwb3MpKSAlPiUgdW5pcXVlKCkKClNwMjBfc2hhcmVkID0gU3AyMF9mZXJyZXQgJT4lIGZpbHRlcihudHZhcnBvcyAlaW4lIFNwMjBfc3RvY2tfbnR2YXJwb3MpICU+JSBmaWx0ZXIoKG50dmFycG9zICVpbiUgU3AyMF9mZXJyZXRfbnR2YXJwb3MpKSAlPiUgdW5pcXVlKCkKU3AyMF9kZW5vdm8gPSBTcDIwX2ZlcnJldCAlPiUgZmlsdGVyKChudHZhcnBvcyAlaW4lIFNwMjBfZmVycmV0X250dmFycG9zKSkgJT4lIGZpbHRlcighKG50dmFycG9zICVpbiUgU3AyMF9zdG9ja19udHZhcnBvcykpICU+JSB1bmlxdWUoKQpgYGAKCmBgYHtyfQpzdG9ja19zaGFyZWQgPSByYmluZChGMTdfc2hhcmVkLCBXMTdfc2hhcmVkLCBTbTE4X3NoYXJlZCwgU3AxOV9zaGFyZWQsIFNwMjBfc2hhcmVkKSAlPiUgdW5pcXVlKCkKc3RvY2tfc2hhcmVkJGFhdmFyID0gcGFzdGUwKHN0b2NrX3NoYXJlZCRtYWpvcmFhLHN0b2NrX3NoYXJlZCRhYXBvcyxzdG9ja19zaGFyZWQkbWlub3JhYSkKCmZlcnVuaXF1ZSA9IHJiaW5kKEYxN19kZW5vdm8sIFcxN19kZW5vdm8sIFNtMThfZGVub3ZvLCBTcDE5X2Rlbm92bywgU3AyMF9kZW5vdm8pICU+JSB1bmlxdWUKZmVydW5pcXVlJGFhdmFyID0gcGFzdGUwKGZlcnVuaXF1ZSRtYWpvcmFhLGZlcnVuaXF1ZSRhYXBvcyxmZXJ1bmlxdWUkbWlub3JhYSkKd3JpdGUuY3N2KGZlcnVuaXF1ZSwgIkFsbFZhck5vdEluU3RvY2suY3N2IikKCmROZFNfZmVydW5pcXVlID0gZ3JvdXBfYnkoZmVydW5pcXVlLCBkaWV0LCBpbmZfcm91dGUsZmVycmV0SUQsIG5vbnN5bikgJT4lIHRhbGx5KCkgJT4lIAogIGZpbHRlcighKGlzLm5hKG5vbnN5bikpKSAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoZmVycmV0SUQsIGRpZXQsaW5mX3JvdXRlKSwgbmFtZXNfZnJvbSA9IG5vbnN5biwgdmFsdWVzX2Zyb20gPSBuKSAlPiUKICBtdXRhdGUoZE5kU19wZXJfZmVycmV0ID0gbm9uc3luL3N5bikgJT4lCiAgZmlsdGVyKCEoaXMubmEoZE5kU19wZXJfZmVycmV0KSkpICU+JSAjZmVycmV0cyB3aXRoIDAgbm9uc3luIG9yIDAgc3luIHdpdGggcHJvZHVjZSBhIGROZFMgPSBOQSwgcmVtb3ZlIHRoZXNlCiAgZ3JvdXBfYnkoZGlldCxpbmZfcm91dGUpICU+JSBtdXRhdGUoYXZnX3Blcl9kaWV0X2luZnJvdXRlID0gbWVhbihkTmRTX3Blcl9mZXJyZXQpKQoKZE5kU19sbiA9IGZpbHRlcihkTmRTX2ZlcnVuaXF1ZSwgZGlldCA9PSAiTGVhbiIgJiBpbmZfcm91dGUgPT0gIkNvbnRhY3QiKSAlPiUgdW5ncm91cCgpCmROZFNfb2IgPSBmaWx0ZXIoZE5kU19mZXJ1bmlxdWUsIGRpZXQgPT0gIk9iZXNlIiAmIGluZl9yb3V0ZSA9PSAiQ29udGFjdCIpICU+JSB1bmdyb3VwKCkKdC50ZXN0KGROZFNfbG4kZE5kU19wZXJfZmVycmV0LCBkTmRTX29iJGROZFNfcGVyX2ZlcnJldCkKCmdncGxvdChkTmRTX2ZlcnVuaXF1ZSwgYWVzKHkgPSBkTmRTX3Blcl9mZXJyZXQsIHggPSBkaWV0KSkgKwogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IGRpZXQpKSArCiAgZ2VvbV92aW9saW4oYWxwaGEgPSAwLjUsIGFlcyhmaWxsID0gZGlldCkpICsKICBmYWNldF9ncmlkKH5pbmZfcm91dGUpICsKICBEaWV0Y29sU2NhbGVfZmlsbCArCiAgUGxvdFRoZW1lMQpgYGAKClNOViBMb2NhdGlvbiBjb21wYXJlZCB0byBzdG9jawpgYGB7cn0KU3RvY2tTaGFyZWRQbG90ID0gZ2dwbG90KHN0b2NrX3NoYXJlZCwgYWVzKHggPSBudHBvcywgeSA9IGZlcnJldElEKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGlldCwgc2hhcGUgPSBjb2hvcnQpLCBzaXplID0gMikgKwogIGZhY2V0X2dyaWQoaW5mX3JvdXRlfnNlZ21lbnQsIGRyb3AgPSBGQUxTRSkgKwogIFBsb3RUaGVtZTEgKwogIERpZXRjb2xTY2FsZSArCiAgZ2d0aXRsZSgiU05WcyBmb3VuZCBpbiBzdG9jayIpCnByaW50KFN0b2NrU2hhcmVkUGxvdCkKZ2dzYXZlKFN0b2NrU2hhcmVkUGxvdCwgZmlsZSA9ICJTdG9ja1NoYXJlZFBsb3QucGRmIiwgaGVpZ2h0ID0gMzAsIHdpZHRoID0gMTUsIHBhdGggPSBzYXZlZGlyKQoKRmVyVW5pcXVlUGxvdCA9IGdncGxvdChmZXJ1bmlxdWUsIGFlcyh4ID0gbnRwb3MsIHkgPSBmZXJyZXRJRCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRpZXQpKSArCiAgZmFjZXRfZ3JpZChpbmZfcm91dGV+c2VnbWVudCkgKwogIFBsb3RUaGVtZTEgKwogIERpZXRjb2xTY2FsZSArCiAgZ2d0aXRsZSgiU05WcyBub3QgZm91bmQgaW4gc3RvY2siKQpwcmludChGZXJVbmlxdWVQbG90KQpnZ3NhdmUoRmVyVW5pcXVlUGxvdCwgZmlsZSA9ICJGZXJVbmlxdWVQbG90LnBkZiIsIHBhdGggPSBzYXZlZGlyKQpgYGAKCiMgU2hhcmVkIGRlIG5vdm8gU05WUwpgYGB7cn0KZmVydW5pcXVlJG50dmFyID0gcGFzdGUwKGZlcnVuaXF1ZSRzZWdtZW50LCJfIixmZXJ1bmlxdWUkbWFqb3IsZmVydW5pcXVlJG50cG9zLGZlcnVuaXF1ZSRtaW5vcikKCnNoYXJlZF92YXJzID0gZmVydW5pcXVlICU+JSAKICBncm91cF9ieShudHZhcixmZXJyZXRJRCkgJT4lIAogIHRhbGx5KCkgJT4lCiAgZ3JvdXBfYnkobnR2YXIpICU+JSAjIFRoaXMgaXMgdG8gcHJldmVudCBkb3VibGUgY291bnRpbmcgdmFyaWFudHMgd2l0aGluIGEgc2FtZSBmZXJyZXQgYnV0IGRpZmZlcmVudCBkcGkKICB0YWxseSgpICU+JSBmaWx0ZXIobiA+IDEpICU+JSB1bmlxdWUoKQoKIyAxMDAgdmFyaWFudHMgdGhhdCBhcmUgc2hhcmVkIGJldHdlZW4gYW55IGZlcnJldHMKc2hhcmVkX2Rlbm92b21pbm9ycyA9IHVuaXF1ZShzaGFyZWRfdmFycyRudHZhcikKZGZfYWxsc2hhcmVkID0gZmlsdGVyKGZlcnVuaXF1ZSwgbnR2YXIgJWluJSBzaGFyZWRfZGVub3ZvbWlub3JzKQoKYGBgCgojIE9iZXNlLSBhbmQgbGVhbi1zcGVjaWZpYyBTTlZzCmBgYHtyfQpvX3ZhciA9IGZpbHRlcihkZl9hbGxzaGFyZWQsIGRpZXQgPT0gIk9iZXNlIikgCm9fdmFyID0gdW5pcXVlKG9fdmFyJG50dmFyKQoKbF92YXIgPSBmaWx0ZXIoZGZfYWxsc2hhcmVkLCBkaWV0ID09ICJMZWFuIikgCmxfdmFyID0gdW5pcXVlKGxfdmFyJG50dmFyKQoKZGlldF92YXIgPC0gbGlzdChPYmVzZSA9IG9fdmFyLCBMZWFuID0gbF92YXIpCgojIFZlbm4gZGlhZ3JhbSBvZiBvYmVzZSBhbmQgbGVhbiBkZSBub3ZvIHNoYXJlZCBTTlZzCkRpZXRVbmlxdWVTTlZTID0gZ2dWZW5uRGlhZ3JhbShkaWV0X3ZhcikKcHJpbnQoRGlldFVuaXF1ZVNOVlMpCmdnc2F2ZShEaWV0VW5pcXVlU05WUywgZmlsZSA9ICJEaWV0VW5pcXVlU05WUy5wZGYiLCBwYXRoID0gc2F2ZWRpcikKCiMgMTAwIHRvdGFsIC0gNjcgc2hhcmVkIGJldHdlZW4gb2Jlc2UgYW5kIGxlYW4sIDIwIG9iZXNlIHNwZWNpZmljLCAxMyBsZWFuIHNwZWNpZmljIApgYGAKCmBgYHtyfQpsZWFuID0gZGZfYWxsc2hhcmVkICU+JQogIGZpbHRlcihudHZhciAlaW4lIGxfdmFyKSAlPiUKICBmaWx0ZXIoIShudHZhciAlaW4lIG9fdmFyKSkgJT4lIAogIHVuaXF1ZSgpCnVuaXF1ZShsZWFuJG50dmFyKQoKbGVhbiRmZXJyZXRJRF92YXIgPSBwYXN0ZTAobGVhbiRmZXJyZXRJRCwiXyIsbGVhbiRudHZhcikKCnJlcGVhdHNfbGVhbiA9IGxlYW4gJT4lIAogIGdyb3VwX2J5KG50dmFyLGZlcnJldElEKSAlPiUgCiAgdGFsbHkoKSAlPiUKICBncm91cF9ieShudHZhcikgJT4lICMgVGhpcyBpcyB0byBwcmV2ZW50IGRvdWJsZSBjb3VudGluZyB2YXJpYW50cyB3aXRoaW4gYSBzYW1lIGZlcnJldCBidXQgZGlmZmVyZW50IGRwaQogIHRhbGx5KCkgJT4lIHVuaXF1ZSgpCgpsZWFuID0gbWVyZ2UobGVhbiwgcmVwZWF0c19sZWFuLCBieSA9IGMoIm50dmFyIikpICU+JSB1bmlxdWUoKQoKb2Jlc2UgPSBkZl9hbGxzaGFyZWQgJT4lIAogIGZpbHRlcihudHZhciAlaW4lIG9fdmFyKSAlPiUgCiAgZmlsdGVyKCEobnR2YXIgJWluJSBsX3ZhcikpICU+JQogIHVuaXF1ZSgpCnVuaXF1ZShvYmVzZSRudHZhcikKCm9iZXNlJGZlcnJldElEX3ZhciA9IHBhc3RlMChvYmVzZSRmZXJyZXRJRCwiXyIsb2Jlc2UkbnR2YXIpCgpyZXBlYXRzX29iZXNlID0gb2Jlc2UgJT4lIAogIGdyb3VwX2J5KG50dmFyLGZlcnJldElEKSAlPiUgCiAgdGFsbHkoKSAlPiUKICBncm91cF9ieShudHZhcikgJT4lICMgVGhpcyBpcyB0byBwcmV2ZW50IGRvdWJsZSBjb3VudGluZyB2YXJpYW50cyB3aXRoaW4gYSBzYW1lIGZlcnJldCBidXQgZGlmZmVyZW50IGRwaQogIHRhbGx5KCkgJT4lCiAgdW5pcXVlKCkKCm9iZXNlID0gbWVyZ2Uob2Jlc2UsIHJlcGVhdHNfb2Jlc2UsIGJ5ID0gYygibnR2YXIiKSkgJT4lIHVuaXF1ZSgpCgpkaWV0dW5pcXVlID0gcmJpbmQobGVhbixvYmVzZSkgJT4lIHVuaXF1ZSgpCmRpZXR1bmlxdWUkZmVycmV0X251bSA9IGRpZXR1bmlxdWUkbgpkaWV0dW5pcXVlID0gc2VsZWN0KGRpZXR1bmlxdWUsICEobikpCmBgYAoKYGBge3J9CiNoYWQgdG8gbG9vayB1cCB0aGVzZSBwb3NpdGlvbnMgbWFudWFsbHkKTVBfRzQ1OUEgPSBmaWx0ZXIoZGlldHVuaXF1ZSwgbnR2YXIgPT0gIkg5TjJfTVBfRzQ1OUEiKSAlPiUgdW5pcXVlKCkKTVBfRzQ1OUEkbm9uc3luID0gInN5biIKTVBfRzQ1OUEkYWF2YXIgPSAiUTE1M1EiCk1QX1Q0NDRDID0gZmlsdGVyKGRpZXR1bmlxdWUsIG50dmFyID09ICJIOU4yX01QX1Q0NDRDIikgJT4lIHVuaXF1ZSgpCk1QX1Q0NDRDJG5vbnN5biA9ICJzeW4iCk1QX1Q0NDRDJGFhdmFyID0gIkMxNDhDIgpNUF9HMzM5QSA9IGZpbHRlcihkaWV0dW5pcXVlLCBudHZhciA9PSAiSDlOMl9NUF9HMzM5QSIpICU+JSB1bmlxdWUoKQpNUF9HMzM5QSRub25zeW4gPSAic3luIgpNUF9HMzM5QSRhYXZhciA9ICJLMTEzSyIKCk1QcyA9IGMoIkg5TjJfTVBfRzQ1OUEiLCJIOU4yX01QX1Q0NDRDIiwiSDlOMl9NUF9HMzM5QSIpCnJlc3QgPSBmaWx0ZXIoZGlldHVuaXF1ZSwgIShudHZhciAlaW4lIE1QcykpICU+JSB1bmlxdWUoKQpkaWV0dW5pcXVlID0gcmJpbmQocmVzdCwgTVBfRzQ1OUEsTVBfVDQ0NEMsTVBfRzMzOUEpCmBgYAoKIyBBRiBhbmQgZW1lcmdlbmNlIG9mIG9iZXNlLXNwZWNpZmljIHZhcmlhbnRzcwpgYGB7cn0KIyBXaGF0IGlzIHRoZSBBRiBkaXN0cmlidXRpb24gb2Ygb2Jlc2Utc3BlY2lmaWMgdmFyaWFudHMKZ2dwbG90KGZpbHRlcihkaWV0dW5pcXVlLCBkaWV0ID09ICJPYmVzZSIgJiBub25zeW4gPT0gIm5vbnN5biIgJiBmZXJyZXRfbnVtID09IDIpLCBhZXMoeCA9IG1pbm9yZnJlcSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMDEpICsKICBQbG90VGhlbWUxCgpnZ3Bsb3QoZmlsdGVyKGRpZXR1bmlxdWUsIGRpZXQgPT0gIk9iZXNlIiAmIG5vbnN5biA9PSAibm9uc3luIiAmIGZlcnJldF9udW0gPT0gMiksIGFlcyh4ID0gaW5mX3JvdXRlLCB5ID0gbWlub3JmcmVxKSkgKwogIGdlb21fYm94cGxvdCgpICsKICAjZmFjZXRfZ3JpZCh+aW5mX3JvdXRlKSArCiAgUGxvdFRoZW1lMQoKIyBPYmVzZSBhcGFkdGF0aW9uIC0+IGhpZ2hlciBBRiB0aGFuIG5vbiBzaGFyZWQ/Cm9faW4gPSBmaWx0ZXIoZGlldHVuaXF1ZSwgZGlldCA9PSAiT2Jlc2UiICYgbm9uc3luID09ICJub25zeW4iICYgZmVycmV0X251bSA9PSAyICYgaW5mX3JvdXRlID09ICJJbmRleCIpCm9fY28gPSBmaWx0ZXIoZGlldHVuaXF1ZSwgZGlldCA9PSAiT2Jlc2UiICYgbm9uc3luID09ICJub25zeW4iICYgZmVycmV0X251bSA9PSAyICYgaW5mX3JvdXRlID09ICJDb250YWN0IikKdC50ZXN0KG9faW4kbWlub3JmcmVxLCBvX2NvJG1pbm9yZnJlcSkKCiMgRGlldCBhZGFwdGF0aW9uIChsZWFuIGFuZCBvYmVzZSkgLT4gaGlnaGVyIEFGIHRoYW4gbm9uIHNoYXJlZD8KaW5kID0gZmlsdGVyKGRpZXR1bmlxdWUsIG5vbnN5biA9PSAibm9uc3luIiAmIGZlcnJldF9udW0gPT0gMiAmIGluZl9yb3V0ZSA9PSAiSW5kZXgiKQojdC50ZXN0KGluZCRtaW5vcmZyZXEsbm9uX3NoYXJlJG1pbm9yZnJlcSkKIwpgYGAKCmBgYHtyfQojIERvIHRoZXkgcGVyc2lzdApsZWFuMiA9IGZlcnVuaXF1ZSAlPiUgCiAgZmlsdGVyKG50dmFyICVpbiUgbF92YXIpICU+JSAKICBmaWx0ZXIoIShudHZhciAlaW4lIG9fdmFyKSkgJT4lIAogIHVuaXF1ZSgpCmxlYW4yJGZlcnJldElEX3ZhciA9IHBhc3RlMChsZWFuMiRmZXJyZXRJRCwiXyIsbGVhbjIkbnR2YXIpCgpyZXBlYXRzX2xlYW4yID0gbGVhbjIgJT4lIAogIG11dGF0ZShjb3VudCA9IDEpICU+JQogIGdyb3VwX2J5KG50dmFyLGZlcnJldElEKSAlPiUgbXV0YXRlKGRheV9udW0gPSBzdW0oY291bnQpKSAlPiUgdW5ncm91cCgpCgpsZWFuX2ZlcnMgPSBzZWxlY3QocmVwZWF0c19sZWFuMiwgbnR2YXIsIGZlcnJldElEKSAlPiUgdW5pcXVlKCkgJT4lIGdyb3VwX2J5KG50dmFyKSAlPiUgdGFsbHkoKQpsZWFuX2ZlcnMkZmVyX251bSA9IGxlYW5fZmVycyRuCmxlYW5fZmVycyA9IHNlbGVjdChsZWFuX2ZlcnMsICEobikpCmxlYW5fd3JlcCA9IG1lcmdlKHJlcGVhdHNfbGVhbjIsIGxlYW5fZmVycywgYnkgPSAibnR2YXIiKSAlPiUgdW5pcXVlKCkKCiMjIyMKCm9iZXNlMiA9IGZlcnVuaXF1ZSAlPiUgCiAgZmlsdGVyKG50dmFyICVpbiUgb192YXIpICU+JSAKICBmaWx0ZXIoIShudHZhciAlaW4lIGxfdmFyKSkgJT4lCiAgdW5pcXVlKCkKb2Jlc2UyJGZlcnJldElEX3ZhciA9IHBhc3RlMChvYmVzZTIkZmVycmV0SUQsIl8iLG9iZXNlMiRudHZhcikKCnJlcGVhdHNfb2Jlc2UyID0gb2Jlc2UyICU+JSAKICBtdXRhdGUoY291bnQgPSAxKSAlPiUKICBncm91cF9ieShudHZhcixmZXJyZXRJRCkgJT4lIG11dGF0ZShkYXlfbnVtID0gc3VtKGNvdW50KSkgJT4lIHVuZ3JvdXAoKSAKb2JfZmVycyA9IHNlbGVjdChyZXBlYXRzX29iZXNlMiwgbnR2YXIsIGZlcnJldElEKSAlPiUgdW5pcXVlKCkgJT4lIGdyb3VwX2J5KG50dmFyKSAlPiUgdGFsbHkoKQpvYl9mZXJzJGZlcl9udW0gPSBvYl9mZXJzJG4Kb2JfZmVycyA9IHNlbGVjdChvYl9mZXJzLCAhKG4pKQpvYmVzZV93cmVwID0gbWVyZ2UocmVwZWF0c19vYmVzZTIsIG9iX2ZlcnMsIGJ5ID0gIm50dmFyIikgJT4lIHVuaXF1ZSgpCgpkaWV0dW5pcXVlX3JlcGVhdHMgPSByYmluZChvYmVzZV93cmVwLGxlYW5fd3JlcCkgJT4lIHVuaXF1ZSgpCmBgYAoKYGBge3J9Cm1ldGFfZ29vZCA9IGZpbHRlcihtZXRhLCBxdWFsaXR5ID09ICJnb29kIikgJT4lIHNlbGVjdChzYW1wbGUsIHF1YWxpdHkpCmRpZXR1bmlxdWVfcmVwZWF0c196ZXJvcyA9IG1lcmdlKGRpZXR1bmlxdWVfcmVwZWF0cywgbWV0YV9nb29kLCBhbGwgPSBUUlVFKSAlPiUgdW5pcXVlKCkKcGVyc2lzdGVuY2UgPSBnZ3Bsb3QoZmlsdGVyKGRpZXR1bmlxdWVfcmVwZWF0cywgbm9uc3luID09ICJub25zeW4iICYgZmVyX251bSA9PSAyKSwgYWVzKHggPSBEUEksIHkgPSBtaW5vcmZyZXEpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBudHZhcikpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gbnR2YXIpKSArCiAgZmFjZXRfZ3JpZCh+ZmVycmV0SUQpICsKICBQbG90VGhlbWUxCnByaW50KHBlcnNpc3RlbmNlKQpnZ3NhdmUocGVyc2lzdGVuY2UsIGZpbGVuYW1lID0gInBlcnNpc3RlbmNlLnBkZiIsIHBhdGggPSBzYXZlZGlyLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSA1KQpgYGAKCmBgYHtyfQojIEVtZXJnZW5jZQp0aW1pbmcgPSBmaWx0ZXIoZGlldHVuaXF1ZSwgZGlldCA9PSAiT2Jlc2UiICYgbm9uc3luID09ICJub25zeW4iICYgZmVycmV0X251bSA9PSAyKSAlPiUKICBtdXRhdGUoY291bnQgPSAxKSAlPiUgCiAgZ3JvdXBfYnkoaW5mX3JvdXRlLCBEUEkpICU+JQogIG11dGF0ZShwZXJkYXkgPSBzdW0oY291bnQpKSAlPiUKICBncm91cF9ieShpbmZfcm91dGUpICU+JSAKICBtdXRhdGUocGVyZ3JvdXAgPSBzdW0oY291bnQpKSAlPiUKICBtdXRhdGUoZGF5X3JhdGlvID0gcGVyZGF5IC8gcGVyZ3JvdXApICU+JQogIHNlbGVjdChEUEksaW5mX3JvdXRlLCBwZXJkYXkscGVyZ3JvdXAsIGRheV9yYXRpbykgJT4lIHVuaXF1ZSgpCgpnZ3Bsb3QodGltaW5nLCBhZXMoeCA9IERQSSwgeSA9IGRheV9yYXRpbykpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF9ncmlkKH5pbmZfcm91dGUpICsKICBQbG90VGhlbWUxCgp0aW1pbmdfYnlkaWV0ID0gZmlsdGVyKGRpZXR1bmlxdWUsbm9uc3luID09ICJub25zeW4iICYgZmVycmV0X251bSA9PSAyKSAlPiUKICBtdXRhdGUoY291bnQgPSAxKSAlPiUgCiAgZ3JvdXBfYnkoZGlldCxpbmZfcm91dGUsIERQSSkgJT4lCiAgbXV0YXRlKHBlcmRheSA9IHN1bShjb3VudCkpICU+JQogIGdyb3VwX2J5KGRpZXQsaW5mX3JvdXRlKSAlPiUgCiAgbXV0YXRlKHBlcmdyb3VwID0gc3VtKGNvdW50KSkgJT4lCiAgbXV0YXRlKGRheV9yYXRpbyA9IHBlcmRheSAvIHBlcmdyb3VwKSAlPiUKICBzZWxlY3QoRFBJLGRpZXQsaW5mX3JvdXRlLCBwZXJkYXkscGVyZ3JvdXAsIGRheV9yYXRpbykgJT4lIHVuaXF1ZSgpCgpnZ3Bsb3QodGltaW5nX2J5ZGlldCwgYWVzKHggPSBEUEksIHkgPSBkYXlfcmF0aW8pKSArCiAgZ2VvbV9jb2woKSArCiAgZmFjZXRfZ3JpZChkaWV0fmluZl9yb3V0ZSkgKwogIFBsb3RUaGVtZTEKYGBgCgojIERldGVybWluaW5nIGlmIGRpZXQtdW5pcXVlIHNoYXJlZCB2YXJpYW50cyBhcmUgdHJhbnNtaXR0ZWQKYGBge3J9CmRpZXR1bmlxdWVfcGFpcnMgPSBtZXJnZShkaWV0dW5pcXVlLCBwYWlycywgYnkgPSBjKCJmZXJyZXRJRCIpKQoKc2hhcmVkID0gZmlsdGVyKGRpZXR1bmlxdWVfcGFpcnMsIGZlcnJldF9udW0gPiAxKQp0ID0gdW5pcXVlKHNoYXJlZCRudHZhcikKCnRyYW5zbWl0dGVkID0gZGF0YS5mcmFtZSgpCgpmb3IoaSBpbiB0KXsKICBwcmludChpKQogIGRmID0gZmlsdGVyKHNoYXJlZCwgbnR2YXIgPT0gaSkgCiAgZGYxID0gZGYgJT4lIAogIGdyb3VwX2J5KG50dmFyLGZlcnJldElELHBhaXJfbnVtYmVycykgJT4lIHRhbGx5KCkgJT4lICN0aGlzIGlzIHRvIGF2b2lkIGRvdWJsZSBjb3VudGluZyB2YXJpYW50cyBwcmVzZW50IGF0IG11bHRpcGxlIERQSSBpbiBzYW1lIGZlcnJldAogIGdyb3VwX2J5KHBhaXJfbnVtYmVycykgJT4lIHRhbGx5KCkKICAjIGhlcmUgYSAyIG1lYW5zIHRoYXQgdGhlIHR3byBmZXJyZXRzIGFyZSBpbiB0aGUgc2FtZSB0cmFuc21pc3Npb24gcGFpciBhbmQgYSAxIGluZGljYXRlcyBkaWZmZXJlbnQgdHJhbnNtaXNzaW9uIHBhaXJzCiAgZGYyID0gbWVyZ2UoZGYsIGRmMSwgYnkgPSBjKCJwYWlyX251bWJlcnMiKSkKICAjIGFkZCB0aGlzIGluZm9ybWF0aW9uIGJhY2sgaW50byB0aGUgZGF0YWZyYW1lCiAgZGYyJHRyYW5zbWlzc2lvbiA9IGRmMiRuCiAgdHJhbnNtaXR0ZWQgPSByYmluZCh0cmFuc21pdHRlZCwgZGYyKQp9CgojZm9ybWF0dGluZyBzdHVmZgp0cmFuc21pdHRlZCR0cmFuc21pc3Npb24gPSBhcy5jaGFyYWN0ZXIodHJhbnNtaXR0ZWQkbikKdHJhbnNtaXR0ZWQgPSB0cmFuc21pdHRlZCAlPiUgc2VsZWN0KCEobikpCmBgYAoKIyBSZW1vdmluZyBwb3NzaWJsZSB0cmFuc21pc3Npb25zIHNpbmNlIHRoZXkgd291bGQgbm90IGJlIGNvbnNpZGVyZWQgcmVjdXJyZW50IApgYGB7cn0KcmVjdXJyZW50ID0gZmlsdGVyKHRyYW5zbWl0dGVkLCB0cmFuc21pc3Npb24gPT0gIjEiKQpzZWxlY3QocmVjdXJyZW50LCBudHZhciwgZGlldCkgJT4lIHVuaXF1ZSgpICU+JSBjb3VudChkaWV0KQpyZWN1cnJlbnRfZE5kUyA9IGdyb3VwX2J5KHJlY3VycmVudCwgZGlldCwgbm9uc3luKSAlPiUgdGFsbHkoKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG5vbnN5biwgdmFsdWVzX2Zyb20gPSBuKSAlPiUKICBtdXRhdGUoZE5kUyA9IG5vbnN5bi9zeW4pCgpEaWV0VW5pcXVlX1JlY3VycmVudCA9IGdncGxvdChyZWN1cnJlbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IG50cG9zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBmYWN0b3Ioc2VnbWVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoJ0g5TjJfTlMnLCdIOU4yX01QJywnSDlOMl9OQScsJ0g5TjJfTlAnLCdIOU4yX0hBJywnSDlOMl9QQScsJ0g5TjJfUEIxJywnSDlOMl9QQjInKSkpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBub25zeW4sIHNpemUgPSAyKSkgKyAKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihyZWN1cnJlbnQsIGZlcnJldF9udW0gPT0gMiwgbm9uc3luID09ICJub25zeW4iKSwgYWVzKGxhYmVsID0gYWF2YXIsIHZqdXN0ID0gMiwgaGp1c3QgPSAwLjUpKSArCiAgeGxhYigiTnVjbGVvdGlkZSBwb3NpdGlvbiIpICsKICB5bGFiKCJTZWdtZW50IikgKwogIGZhY2V0X2dyaWQofmRpZXQpICsKICBQbG90VGhlbWUxCnByaW50KERpZXRVbmlxdWVfUmVjdXJyZW50KQpnZ3NhdmUoRGlldFVuaXF1ZV9SZWN1cnJlbnQsIGZpbGUgPSAiRGlldFVuaXF1ZV9SZWN1cnJlbnQucGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSwgcGF0aCA9IHNhdmVkaXIpCmBgYAojIExvb2tpbmcgYXQgdHJhbnNtaXR0ZWQgbWlub3IgdmFycwpgYGB7cn0KdHJhbnNfdmFyID0gZmlsdGVyKHRyYW5zbWl0dGVkLCB0cmFuc21pc3Npb24gPT0gIjIiKQpzZWxlY3QodHJhbnNfdmFyLCBudHZhciwgZGlldCkgJT4lIHVuaXF1ZSgpICU+JSBjb3VudChkaWV0KQoKdHJhbnNtaXR0ZWRfZGVub3ZvX21pbm9ycyA9IGdncGxvdCh0cmFuc192YXIsYWVzKHggPSBudHBvcyx5ID0gZmFjdG9yKHNlZ21lbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCdIOU4yX05TJywnSDlOMl9NUCcsJ0g5TjJfTkEnLCdIOU4yX05QJywnSDlOMl9IQScsJ0g5TjJfUEEnLCdIOU4yX1BCMScsJ0g5TjJfUEIyJykpKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gbm9uc3luLCBzaXplID0gMikpICsgCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIodHJhbnNfdmFyLCBmZXJyZXRfbnVtID09IDIpLCBhZXMobGFiZWwgPSBhYXZhciwgdmp1c3QgPSAyLCBoanVzdCA9IDAuNSkpICsKICB4bGFiKCJOdWNsZW90aWRlIHBvc2l0aW9uIikgKwogIHlsYWIoIlNlZ21lbnQiKSArCiAgZmFjZXRfZ3JpZChwYWlyX251bWJlcnMrcGFpcl9kaWV0c35pbmZfcm91dGUpICsKICBQbG90VGhlbWUyCnByaW50KHRyYW5zbWl0dGVkX2Rlbm92b19taW5vcnMpCmdnc2F2ZSh0cmFuc21pdHRlZF9kZW5vdm9fbWlub3JzLCBmaWxlID0gIkRpZXRVbmlxdWVfVHJhbnNtaXR0ZWQucGRmIiwgIHdpZHRoID0gNywgaGVpZ2h0ID0gNSwgcGF0aCA9IHNhdmVkaXIpCmBgYAoKIyBTTlZzIHNoYXJlZCBiZXR3ZWVuIGRpZXQgZ3JvdXBzCmBgYHtyfQpzaGFyZWQgPSBkZl9hbGxzaGFyZWQgJT4lIAogIGZpbHRlcihudHZhciAlaW4lIG9fdmFyKSAlPiUgCiAgZmlsdGVyKG50dmFyICVpbiUgbF92YXIpICU+JSAKICB1bmlxdWUoKQpzaGFyZWQkZmVycmV0SURfdmFyID0gcGFzdGUwKHNoYXJlZCRmZXJyZXRJRCwiXyIsc2hhcmVkJG50dmFyKQoKcmVwZWF0c19zaGFyZWQgPSBzaGFyZWQgJT4lIAogIGdyb3VwX2J5KG50dmFyLGZlcnJldElEKSAlPiUgCiAgdGFsbHkoKSAlPiUKICBncm91cF9ieShudHZhcikgJT4lCiAgdGFsbHkoKQojIHRoaXMgaXMgdG8gbWFrZSBzdXJlIEknbSBub3QgcmVwZWF0ZWRseSBjb3VudGluZyBhIHZhcmlhbnQgZm91bmQgaW4gb25lIGZlcnJldCBidXQgbXVsdGlwbGUgZGF5cyAKCnNoYXJlZCA9IG1lcmdlKHNoYXJlZCwgcmVwZWF0c19zaGFyZWQsIGJ5ID0gYygibnR2YXIiKSkgJT4lIHVuaXF1ZSgpCgpTaGFyZWRQbG90ID0gZ2dwbG90KHNoYXJlZCwgCiAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBudHBvcywKICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGZhY3RvcihzZWdtZW50LCBsZXZlbHMgPSBjKCdIOU4yX05TJywnSDlOMl9NUCcsJ0g5TjJfTkEnLCdIOU4yX05QJywnSDlOMl9IQScsJ0g5TjJfUEEnLCdIOU4yX1BCMScsJ0g5TjJfUEIyJykpKSkgKwogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBuLCBjb2xvciA9IG5vbnN5bikpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihzaGFyZWQsIG4gPiA0LCBub25zeW4gPT0gIm5vbnN5biIpLCBhZXMobGFiZWwgPSBhYXZhciwgdmp1c3QgPSAyLCBoanVzdCA9IDAuNSkpICsKICBnZ3RpdGxlKCJOdW1iZXIgb2Ygc2FtcGxlcyBjb250YWluaW5nIGVhY2ggdmFyaWFudCAtIFNoYXJlZCBiZXR3ZWVuIGRpZXQgZ3JvdXBzIikgKwogIHlsYWIoIlNlZ21lbnQiKSArCiAgeGxhYigiTnVjbGVvdGlkZSBQb3NpdGlvbiIpICsKICBQbG90VGhlbWUxCnByaW50KFNoYXJlZFBsb3QpCmdnc2F2ZShTaGFyZWRQbG90LCBmaWxlbmFtZSA9ICJTZWdtZW50U05WUGxvdF9EaWV0U2hhcmVkLnBkZiIsIHBhdGggPSBzYXZlZGlyLCBoZWlnaHQgPSAxMCwgd2lkdGggPSA5KQpgYGAKCiMgRXh0cmFjdGluZyBjb21tb24gbm9uc3lub255bW91cyB2YXJpYW50cyBzaGFyZWQgYmV0d2VlbiBkaWV0IGdyb3VwcwpgYGB7cn0Kbm9uc3luc19zaGFyZWQgPSBmaWx0ZXIoc2hhcmVkLCBub25zeW4gPT0gIm5vbnN5biIgJiBuID4gMSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KG50dmFyLGFhdmFyLG1pbm9yZnJlcSxuKSAlPiUKICB1bmlxdWUoKSAlPiUKICBhcnJhbmdlKGRlc2MobikpCgp3cml0ZS50YWJsZShub25zeW5zX3NoYXJlZCwgIm5vbnN5bnNfc2hhcmVkLmNzdiIsIHNlcCA9ICIsIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyBBcmUgdGhlcmUgZGlmZmVyZW5jZXMgaW4gQUYgYmV0d2VlbiBkaWV0LXNwZWNpZmljIGFuZCBub24tZGlldC1zcGVjaWZpYyBzaGFyZWQgdmFycz8KYGBge3J9CmdncGxvdChzaGFyZWQsIGFlcyh4ID0gbWlub3JmcmVxKSkgKwogIGdlb21faGlzdG9ncmFtKCkKZ2dwbG90KHRyYW5zbWl0dGVkLCBhZXMoeCA9IG1pbm9yZnJlcSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpCgp0LnRlc3Qoc2hhcmVkJG1pbm9yZnJlcSwgdHJhbnNtaXR0ZWQkbWlub3JmcmVxKQpgYGAKCiMgQXJlIHRoZXJlIGRpZmZlcmVuY2VzIGluIGFsbGVsZSBmcmVxIHdpdGhpbiB0aGUgc2hhcmVkIHZhcmlhbnRzPwpgYGB7cn0KZ2dwbG90KHNoYXJlZCwgYWVzKHggPSBtaW5vcmZyZXEpKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhncm91cCA9IGZhY3RvcihuLCBsZXZlbHMgPSBjKCIyIiwiMyIsIjQiLCI1IiwiNiIsIjciLCI4IiwiOSIsIjEwIiwiMjIiKSksIAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKG4sIGxldmVscyA9IGMoIjIiLCIzIiwiNCIsIjUiLCI2IiwiNyIsIjgiLCI5IiwiMTAiLCIyMiIpKSwKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSkKCnNlbGVjdChub25zeW5zX3NoYXJlZCwgIW1pbm9yZnJlcSkgJT4lIHVuaXF1ZSgpICU+JSBnZ3Bsb3QoLiwgYWVzKHggPSBuKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpCiMgZGV0ZXJtaW5pbmcgY3V0b2ZmcyBmb3IgaGlnaCBhbmQgbG93IHNoYXJlZAoKbG93X3NoYXJlZCA9IGZpbHRlcihzaGFyZWQsIG4gPCA1KSAlPiUgdW5pcXVlKCkgJT4lIG11dGF0ZShjYXQgPSAibG93IikKaGlnaF9zaGFyZWQgPSBmaWx0ZXIoc2hhcmVkLCBuID4gNSkgJT4lIHVuaXF1ZSgpICU+JSBtdXRhdGUoY2F0ID0gImhpZ2giKQphbGxfc2hhcmVkID0gcmJpbmQobG93X3NoYXJlZCwgaGlnaF9zaGFyZWQpCgpnZ3Bsb3QobG93X3NoYXJlZCwgYWVzKHggPSBtaW5vcmZyZXEpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAxKQoKZ2dwbG90KGhpZ2hfc2hhcmVkLCBhZXMoeCA9IG1pbm9yZnJlcSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMDEpCgpnZ3Bsb3QoYWxsX3NoYXJlZCwgYWVzKHggPSBtaW5vcmZyZXEpKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhncm91cCA9IGNhdCwgZmlsbCA9IGNhdCksIGFscGhhID0gMC40KQoKdC50ZXN0KGxvd19zaGFyZWQkbWlub3JmcmVxLCBoaWdoX3NoYXJlZCRtaW5vcmZyZXEpCmBgYAoKIyBBcmUgdGhlcmUgZGlmZmVyZW5jZXMgaW4gQUYgYmV0d2VlbiBzaGFyZWQgYW5kIG5vbiBzaGFyZWQgdmFyaWFudHM/CmBgYHtyfQpvbmVmZXJyZXQgPSBzZWxlY3QoZmVydW5pcXVlLG50dmFyLCBtaW5vcmZyZXEsIHNhbXBsZSkgJT4lIHVuaXF1ZSgpICU+JSBjb3VudChudHZhcikgJT4lIGZpbHRlcihuID09IDEpIApvbmVmZXJyZXQgPSB1bmlxdWUob25lZmVycmV0JG50dmFyKQpzaW5nbGVzID0gZmlsdGVyKGZlcnVuaXF1ZSwgbnR2YXIgJWluJSBvbmVmZXJyZXQpICU+JSB1bmlxdWUoKQoKbm9uX3NoYXJlID0gc2VsZWN0KHNpbmdsZXMsIG50dmFyLCBhYXZhciwgbWlub3JmcmVxKSAlPiUgbXV0YXRlKG4gPSAxKQpub25fc2hhcmUkY2F0ID0gIm5vdCBzaGFyZWQiCgpnZ3Bsb3Qobm9uX3NoYXJlLCBhZXMoeCA9IG1pbm9yZnJlcSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMDEpCmFsbF9zaGFyZWQkY2F0ID0gInNoYXJlZCIKCmFsbF9zaGFyZWRfc3ViID0gc2VsZWN0KGFsbF9zaGFyZWQsIG50dmFyLCBhYXZhciwgbWlub3JmcmVxLCBuLCBjYXQpCgp0cnlfYWxsID0gcmJpbmQoYWxsX3NoYXJlZF9zdWIsIG5vbl9zaGFyZSkgJT4lIHVuaXF1ZSgpCgpnZ3Bsb3QodHJ5X2FsbCwgYWVzKHggPSBtaW5vcmZyZXEpKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhncm91cCA9IGNhdCwgZmlsbCA9IGNhdCksIGFscGhhID0gMC40KQoKdC50ZXN0KG5vbl9zaGFyZSRtaW5vcmZyZXEsIGxvd19zaGFyZWQkbWlub3JmcmVxKQp0LnRlc3Qobm9uX3NoYXJlJG1pbm9yZnJlcSwgaGlnaF9zaGFyZWQkbWlub3JmcmVxKQpgYGAKCiMgQ29tYmluaW5nIGFsbCBzaGFyZWQoYnR3IG9iZXNlIGFuZCBsZWFuKSBjb21wYXJlZCB0byBub3Qgc2hhcmVkCmBgYHtyfQpzaGFyZV92X25vc2hhcmVfQUYgPSBnZ3Bsb3QodHJ5X2FsbCwgYWVzKHkgPSBtaW5vcmZyZXEsIHggPSBjYXQsIGNvbG9yID0gY2F0KSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsgCiAgI2dlb21faml0dGVyKGFscGhhID0gMC4zKSArCiAgeWxpbSgwLDAuMSkgKwogIFBsb3RUaGVtZTEKcHJpbnQoc2hhcmVfdl9ub3NoYXJlX0FGKQpnZ3NhdmUoc2hhcmVfdl9ub3NoYXJlX0FGLCBmaWxlbmFtZSA9ICJzaGFyZV92X25vc2hhcmVfQUYucGRmIiwgcGF0aCA9IHNhdmVkaXIsIGhlaWdodCA9IDUsIHdpZHRoID0gOSkKCmdncGxvdCh0cnlfYWxsLCBhZXMoeSA9IG1pbm9yZnJlcSwgeCA9IGNhdCwgY29sb3IgPSBjYXQpKSArCiAgZ2VvbV92aW9saW4oKSArCiAgUGxvdFRoZW1lMQoKdC50ZXN0KG5vbl9zaGFyZSRtaW5vcmZyZXEsIGFsbF9zaGFyZWQkbWlub3JmcmVxKQpgYGAKCiMgSXMgdGhlcmUgYSBkaWZmZXJlbmNlIGluIGZyZXEgb3IgYWJ1bmRhbmNlIGJldHdlZW4gb2Jlc2UgdiBsZWFuIGZlcnJldHMgb2YgdGhlIDY3IG5vbi1kaWV0LXNwZWNpZmljIHNoYXJlZCB2YXJzPwpgYGB7cn0KIyBGcmVxdWVuY3kKZ2dwbG90KHNoYXJlZCwgYWVzKHggPSBkaWV0LCB5ID0gbWlub3JmcmVxKSkgKwogIGdlb21fYm94cGxvdChhZXMoY29sb3IgPSBkaWV0KSkgKwogIERpZXRjb2xTY2FsZSArCiAgUGxvdFRoZW1lMgpzaGFyZWRfbG4gPSBmaWx0ZXIoc2hhcmVkLCBkaWV0ID09ICJMZWFuIikKc2hhcmVkX29iID0gZmlsdGVyKHNoYXJlZCwgZGlldCA9PSAiT2Jlc2UiKQp0LnRlc3Qoc2hhcmVkX2xuJG1pbm9yZnJlcSxzaGFyZWRfb2IkbWlub3JmcmVxKQoKIyBBYnVuZGFuY2UKc2hhcmVkX3ZhcnMgPSBncm91cF9ieShzaGFyZWQsIG50dmFyLCBkaWV0KSAlPiUgdGFsbHkoKSAKCmdncGxvdChzaGFyZWRfdmFycywgYWVzKHggPSBudHZhciwgeSA9IG4sIGZpbGwgPSBkaWV0KSkgKwpnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiNmYWNldF9ncmlkKH5pbmZfcm91dGUpICsKUGxvdFRoZW1lMSArCkRpZXRjb2xTY2FsZV9maWxsCgpkaWZmX3NoYXJlZF92YXJzID0gZ3JvdXBfYnkoc2hhcmVkLCBudHZhciwgZGlldCkgJT4lIAogIHRhbGx5KCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBkaWV0LCB2YWx1ZXNfZnJvbSA9IG4pICU+JSAKICBtdXRhdGUoZGlmZiA9IGFicyhPYmVzZSAtIExlYW4pKSAlPiUgCiAgZmlsdGVyKGRpZmYgPiAyKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoIkxlYW4iLCAiT2Jlc2UiKSwgbmFtZXNfdG8gPSBjKCJkaWV0IikpCiAgCmdncGxvdChkaWZmX3NoYXJlZF92YXJzLCBhZXMoeCA9IG50dmFyLCB5ID0gdmFsdWUsIGZpbGwgPSBkaWV0KSkgKwpnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKI2ZhY2V0X2dyaWQofmluZl9yb3V0ZSkgKwpQbG90VGhlbWUxICsKRGlldGNvbFNjYWxlX2ZpbGwKYGBgCgojSXMgdGhlcmUgYSBkaWZmZXJlbmNlIGluIEFGIG9mIHRoZSB2YXJpYW50cyBmb3VuZCBpbiBvYmVzZSBhbmQgbGVhbiBmZXJyZXRzPwpgYGB7cn0KZ2dwbG90KHNoYXJlZCwgYWVzKHggPSBtaW5vcmZyZXEsIGZpbGwgPSBkaWV0KSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4wMSkgKwogIFBsb3RUaGVtZTEgKwogIGZhY2V0X2dyaWQoaW5mX3JvdXRlfmRpZXQpICsKICBEaWV0Y29sU2NhbGVfZmlsbAoKbyA9IGZpbHRlcihzaGFyZWQsIGluZl9yb3V0ZSA9PSAiSW5kZXgiICYgZGlldCA9PSAiT2Jlc2UiKQpsID0gZmlsdGVyKHNoYXJlZCwgaW5mX3JvdXRlID09ICJJbmRleCIgJiBkaWV0ID09ICJMZWFuIikKdC50ZXN0KG8kbWlub3JmcmVxLCBsJG1pbm9yZnJlcSkKI25vdCBzaWduaWZpY2FudGx5IGRpZmZlcmVudApgYGAKCmBgYHtyfQpvYmVzZV9pbmRleCA9IGZpbHRlcihmZXJ1bmlxdWUsIGRpZXQgPT0gIk9iZXNlIiAmIGluZl9yb3V0ZSA9PSAiSW5kZXgiKSAlPiUgdW5ncm91cCgpCmxlYW5faW5kZXggPSBmaWx0ZXIoZmVydW5pcXVlLCBkaWV0ID09ICJMZWFuIiAmIGluZl9yb3V0ZSA9PSAiSW5kZXgiKSAlPiUgdW5ncm91cCgpCnQudGVzdChvYmVzZV9pbmRleCRtaW5vcmZyZXEsIGxlYW5faW5kZXgkbWlub3JmcmVxKQojIG1lYW5zIGFyZSBub3QgZGlmZmVyZW50CgpvYmVzZV9jb250YWN0ID0gZmlsdGVyKGZlcnVuaXF1ZSwgZGlldCA9PSAiT2Jlc2UiICYgaW5mX3JvdXRlID09ICJDb250YWN0IikgJT4lIHVuZ3JvdXAoKQpsZWFuX2NvbnRhY3QgPSBmaWx0ZXIoZmVydW5pcXVlLCBkaWV0ID09ICJMZWFuIiAmIGluZl9yb3V0ZSA9PSAiQ29udGFjdCIpICU+JSB1bmdyb3VwKCkKdC50ZXN0KG9iZXNlX2NvbnRhY3QkbWlub3JmcmVxLCBsZWFuX2NvbnRhY3QkbWlub3JmcmVxKQojIG1lYW5zIGFyZSBub3QgZGlmZmVyZW50CgojIFFRX1Bsb3Q6IGNvbXBhcmVzIHRoZSBxdWFudGlsZXMgb2YgdHdvIGRpc3RyaWJ1dGlvbnMsIHggPXkgc3VnZ2VzdHMgdGhleSBhcmUgZHJhd24gZnJvbSB0aGUgc2FtZSBkaXN0cmlidXRpb24KcXFub3JtKG9iZXNlX2luZGV4JG1pbm9yZnJlcSwgbWFpbiA9ICJPYmVzZSBJbmRleCAtIFRlc3Qgb2YgTm9ybWFsIERpc3RyaWJ1dGlvbiIpCnFxbm9ybShsZWFuX2luZGV4JG1pbm9yZnJlcSwgbWFpbiA9ICJMZWFuIEluZGV4IC0gVGVzdCBvZiBOb3JtYWwgRGlzdHJpYnV0aW9uIikKIyBuZWl0aGVyIGRpc3RyaWJ1dGlvbiBpcyBub3JtYWwKcXFwbG90KG9iZXNlX2luZGV4JG1pbm9yZnJlcSxsZWFuX2luZGV4JG1pbm9yZnJlcSwgeGxhYiA9ICJPYmVzZSBJbmRleCIsIHlsYWIgPSAiTGVhbiBJbmRleCIpCgpxcW5vcm0ob2Jlc2VfY29udGFjdCRtaW5vcmZyZXEsIG1haW4gPSAiT2Jlc2UgQ29udGFjdCAtIFRlc3Qgb2YgTm9ybWFsIERpc3RyaWJ1dGlvbiIpCnFxbm9ybShsZWFuX2NvbnRhY3QkbWlub3JmcmVxLCBtYWluID0gIkxlYW4gQ29udGFjdCAtIFRlc3Qgb2YgTm9ybWFsIERpc3RyaWJ1dGlvbiIpCiMgbmVpdGhlciBkaXN0cmlidXRpb24gaXMgbm9ybWFsCnFxcGxvdChvYmVzZV9jb250YWN0JG1pbm9yZnJlcSxsZWFuX2NvbnRhY3QkbWlub3JmcmVxLCB4bGFiID0gIk9iZXNlIENvbnRhY3QiLCB5bGFiID0gIkxlYW4gQ29udGFjdCIpCgojIE1hbm4tV2hpdG5leS1XaWxjb3ggdGVzdCAoTWFubi1XaGl0bmV5IFUgdGVzdCk6IHNhbXBsZXMgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCBhbmQgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlcgp3aWxjb3gudGVzdChvYmVzZV9pbmRleCRtaW5vcmZyZXEsbGVhbl9pbmRleCRtaW5vcmZyZXEpCndpbGNveC50ZXN0KG9iZXNlX2NvbnRhY3QkbWlub3JmcmVxLGxlYW5fY29udGFjdCRtaW5vcmZyZXEpCiMgZGlzdHJpYnV0aW9ucyBhcmUgbm90IGRpZmZlcmVudAoKIyBLb2xtb2dvcm92LVNtaXJub3YgdGVzdDogc2FtcGxlcyBhcmUgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGFuZCBpbmRlcGVuZGVudCBvZiBlYWNoIG90aGVyCiMgInNlbnNpdGl2ZSB0byBkaWZmZXJlbmNlcyBpbiBsb2NhdGlvbiBhbmQgc2hhcGUgb2YgdGhlIGVtcGlyaWNhbCBDREZzIG9mIHRoZSB0d28gc2FtcGxlcyIKa3MudGVzdChvYmVzZV9pbmRleCRtaW5vcmZyZXEsbGVhbl9pbmRleCRtaW5vcmZyZXEpCmtzLnRlc3Qob2Jlc2VfY29udGFjdCRtaW5vcmZyZXEsbGVhbl9jb250YWN0JG1pbm9yZnJlcSkKIyBkaXN0cmlidXRpb25zIGFyZSBub3QgZGlmZmVyZW50CmBgYAoK